Trait Ordination Plant Community Analysis

  1. traits

    1. above- and belowground

      1. height & SLA
    2. acquisitive vs. conservative resource-use strategies

      1. rooting depth
    3. collaborative vs. individual resource-use strategies

      1. fine root proportion

      2. thickness of roots

Goal: Examine how traits shift in community compositional (ordinational) space, placing each trait on an axis.

Author: Caryn D. Iwanaga

Updated: 02/06/2025

Libraries

library(tidyverse)
library(dplyr)
library(ggplot2)
library(httr) # read out Dropbox folders
library(vegan)
library(readxl)

Read in Data

cover.dat.labels <- read.csv("https://www.dropbox.com/scl/fi/up8nnzkcpchsr45f8cm92/Compost_Cover_LongClean.csv?rlkey=z2tvaj8t6khadef7ydz782zka&st=qwef9ys0&dl=1") %>%
  mutate(
    nut_trt = factor(ifelse(nut_trt =="C", "+compost", ifelse(nut_trt =="F", "+N fertilizer", ifelse(nut_trt =="N", "control", NA))), levels = c("control", "+N fertilizer", "+compost")),
    ppt_trt = ifelse(ppt_trt == "D", "dry", ifelse(ppt_trt == "XC", "control", ifelse(ppt_trt == "W", "wet", NA))))


# Define a reusable color scale
# custom_colors <- scale_fill_manual(
#   values = c(
#     "control" = rgb(195, 197, 193, maxColorValue = 250),
#     "+N fertilizer" = rgb(87, 62, 92, maxColorValue = 225),
#     "+compost" = rgb(167, 156, 109, maxColorValue = 225)
#   )
# )

custom_colors <- scale_fill_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

# Set a global theme
theme_set(theme_bw())

Make site x species matrix

  1. Calculate relative abundances of species for each site
    1. confused how to aggregate abundances because even grouping by plotid (nut_trt and ppt_trt), year, species, and grazing history (block 1&2 – high, block 3&4 – low) and averaged, the sd are as high as 45.96!
      1. proceeded with these high sd to see what happens (ask Lauren)
    2. try how it is when you split everything by each block (more representative?)
site.df <- 
  cover.dat.labels[, c(1:7, 18:19)] %>% #subset columns
  mutate(
    grazing_hist = ifelse(block == 1 | block == 2, "high", ifelse(block == 3 | block == 4, "low", NA))
  ) %>% # separate by block (grazing intensities)
  group_by(nut_trt, ppt_trt, yr, code4, grazing_hist) %>% # make each code unique -- one value for species abundance for each trt
  summarise(
    # pct_cover,
    abundance = mean(pct_cover)
    # sd = sd(pct_cover)
  )
`summarise()` has grouped output by 'nut_trt', 'ppt_trt', 'yr', 'code4'. You can override using the `.groups` argument.
matrix0 <- spread(
  site.df, 
  code4, 
  abundance, 
  fill = 0)

# make rownames ----
rownames(matrix0) <- paste(matrix0$nut_trt, matrix0$ppt_trt, matrix0$yr, matrix0$grazing_hist, sep = "_")
Warning: Setting row names on a tibble is deprecated.
# delete columns ---- 
matrix <- matrix0[, c(5:79)]

# relativize data with Bray-Curtis dissimilarity
matrix.bray <- decostand(matrix, "total")
rownames(matrix.bray) <- rownames(matrix0)

Split matrix by each block as well

site.block.df <- 
  cover.dat.labels[, c(1:7, 18:19)] %>% #subset columns
  group_by(nut_trt, ppt_trt, yr, code4, block) %>% # make each code unique -- one value for species abundance for each trt
  summarise(
    # pct_cover,
    abundance = mean(pct_cover)
    # sd = sd(pct_cover)
  )
`summarise()` has grouped output by 'nut_trt', 'ppt_trt', 'yr', 'code4'. You can override using the `.groups` argument.
site.block.sd.df <- 
  cover.dat.labels[, c(1:7, 18:19)] %>% #subset columns
  group_by(nut_trt, ppt_trt, yr, code4, block) %>% # make each code unique -- one value for species abundance for each trt
  summarise(
    pct_cover,
    abundance = mean(pct_cover),
    sd = sd(pct_cover)
  )
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.`summarise()` has grouped output by 'nut_trt', 'ppt_trt', 'yr', 'code4', 'block'. You can override using the `.groups` argument.
matrix0.block <- spread(
  site.block.df, 
  code4, 
  abundance, 
  fill = 0)

# make rownames ----
rownames(matrix0.block) <- paste(matrix0.block$nut_trt, matrix0.block$ppt_trt, matrix0.block$yr, matrix0.block$block, sep = "_")
Warning: Setting row names on a tibble is deprecated.
# delete columns ---- 
matrix.block <- matrix0.block[, -c(0:4)]

# relativize data with Bray-Curtis dissimilarity
matrix.block.bray <- decostand(matrix.block, "total")
rownames(matrix.block.bray) <- rownames(matrix0.block)

Run NMDS

Rules of thumb:

  • < 0.05 is excellent

  • 0.05-0.1 is good

  • 0.1-0.2 is fair

  • 0.2-0.3 is cause for concern…

  • > 0.3 is poor, random

All years – low & high grazing

Stress: fair

0.1966553 

Grouping by year and grazing history had most significant clustering shown.

metaMDS()
nmds.comp <- metaMDS(matrix.bray, k=2, trymax = 25)
Run 0 stress 0.2020736 
Run 1 stress 0.2037794 
Run 2 stress 0.1973259 
... New best solution
... Procrustes: rmse 0.07504543  max resid 0.2323388 
Run 3 stress 0.1970656 
... New best solution
... Procrustes: rmse 0.02167554  max resid 0.1184388 
Run 4 stress 0.2112285 
Run 5 stress 0.2016301 
Run 6 stress 0.2034469 
Run 7 stress 0.2100941 
Run 8 stress 0.2020249 
Run 9 stress 0.1990567 
Run 10 stress 0.205915 
Run 11 stress 0.2072425 
Run 12 stress 0.2077976 
Run 13 stress 0.196667 
... New best solution
... Procrustes: rmse 0.01874332  max resid 0.1106696 
Run 14 stress 0.2021165 
Run 15 stress 0.2061482 
Run 16 stress 0.1966667 
... New best solution
... Procrustes: rmse 0.0005495779  max resid 0.002877469 
... Similar to previous best
Run 17 stress 0.2158361 
Run 18 stress 0.21463 
Run 19 stress 0.2120927 
Run 20 stress 0.2037336 
*** Best solution repeated 1 times
nmds.comp # pretty not great stress

Call:
metaMDS(comm = matrix.bray, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray 
Distance: bray 

Dimensions: 2 
Stress:     0.1966667 
Stress type 1, weak ties
Best solution was repeated 1 time in 20 tries
The best solution was from try 16 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray’ 
stressplot(nmds.comp)

plot(nmds.comp, type="t")


nmds1 <- as.data.frame(scores(nmds.comp, choices=c(1), display=c("sites"))) %>%
  mutate(matrix0[, c(0:4)])
nmds2 <- as.data.frame(scores(nmds.comp, choices=c(2), display=c("sites")))

nmds_dat <- cbind(nmds1, nmds2) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_dat, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Nutrient Treatment") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)


ggplot(nmds_dat, aes(NMDS1, NMDS2, color = as.factor(yr), fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Year")


ggplot(nmds_dat, aes(NMDS1, NMDS2, fill = as.factor(ppt_trt), color = as.factor(ppt_trt))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Precipitation Treatment") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)


ggplot(nmds_dat, aes(NMDS1, NMDS2,  fill = as.factor(grazing_hist), color = as.factor(grazing_hist))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Grazing History")


ggplot(nmds_dat, aes(NMDS1, NMDS2,  color = as.factor(grazing_hist), fill = as.factor(yr))) +
  geom_point(aes(fill = as.factor(yr)), shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  labs(title = "Grouped by Grazing History & Year") +
  scale_color_manual(
  values = c(
    "low" = "cyan",
    "high" = "brown",
  "2019" = "salmon",
  "2020" = "limegreen",
  "2021" = "cornflowerblue")
  )

  
ggplot(nmds_dat, aes(NMDS1, NMDS2, color = nut_trt, fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(nut_trt)),
             geom = "polygon",
             fill = NA,  # Makes the ellipse transparent inside
             size = 1) +
  labs(title = "Grouped by Nutrient Treatment & Year") +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

All years – blocks

Stress: cause for concern

0.2329306
metaMDS()
nmds.block.comp <- metaMDS(matrix.block.bray, k=2, trymax = 25)
Run 0 stress 0.2329306 
Run 1 stress 0.2385405 
Run 2 stress 0.2608291 
Run 3 stress 0.2618978 
Run 4 stress 0.2625943 
Run 5 stress 0.2369671 
Run 6 stress 0.2329931 
... Procrustes: rmse 0.002596777  max resid 0.01287822 
Run 7 stress 0.2447034 
Run 8 stress 0.2406908 
Run 9 stress 0.2476092 
Run 10 stress 0.2412944 
Run 11 stress 0.232978 
... Procrustes: rmse 0.002270404  max resid 0.012997 
Run 12 stress 0.23922 
Run 13 stress 0.2497086 
Run 14 stress 0.2478848 
Run 15 stress 0.2365873 
Run 16 stress 0.2329684 
... Procrustes: rmse 0.001740474  max resid 0.01298233 
Run 17 stress 0.2520339 
Run 18 stress 0.248187 
Run 19 stress 0.2380139 
Run 20 stress 0.2333533 
... Procrustes: rmse 0.0115742  max resid 0.112582 
Run 21 stress 0.2489426 
Run 22 stress 0.2400835 
Run 23 stress 0.2421075 
Run 24 stress 0.2510936 
Run 25 stress 0.232944 
... Procrustes: rmse 0.001509127  max resid 0.01190131 
*** Best solution was not repeated -- monoMDS stopping criteria:
    24: stress ratio > sratmax
     1: scale factor of the gradient < sfgrmin
nmds.block.comp

Call:
metaMDS(comm = matrix.block.bray, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.block.bray 
Distance: bray 

Dimensions: 2 
Stress:     0.2329306 
Stress type 1, weak ties
Best solution was not repeated after 25 tries
The best solution was from try 0 (metric scaling or null solution)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.block.bray’ 
stressplot(nmds.block.comp)

plot(nmds.block.comp, type="t")


nmds1 <- as.data.frame(scores(nmds.block.comp, choices=c(1), display=c("sites"))) %>%
  mutate(matrix0.block[, c(0:4)])
nmds2 <- as.data.frame(scores(nmds.block.comp, choices=c(2), display=c("sites")))

nmds_dat.block <- cbind(nmds1, nmds2) %>%
  select(nut_trt:block, NMDS1, NMDS2)
plot
ggplot(nmds_dat.block, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Nutrient Treatment - Blocks") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)


ggplot(nmds_dat.block, aes(NMDS1, NMDS2, color = as.factor(yr), fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Year - Blocks")


ggplot(nmds_dat.block, aes(NMDS1, NMDS2, fill = as.factor(ppt_trt), color = as.factor(ppt_trt))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Precipitation Treatment - Blocks") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)


ggplot(nmds_dat.block, aes(NMDS1, NMDS2,  fill = as.factor(block), color = as.factor(block))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Block")


ggplot(nmds_dat.block, aes(NMDS1, NMDS2,  color = as.factor(block), fill = as.factor(yr))) +
  geom_point(aes(fill = as.factor(yr)), shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(block)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  labs(title = "Grouped by Block & Year - Blocks") +
  scale_color_manual(
  values = c(
    # "low" = "cyan",
    # "high" = "brown",
  "2019" = "salmon",
  "2020" = "limegreen",
  "2021" = "cornflowerblue")
  )

  
ggplot(nmds_dat.block, aes(NMDS1, NMDS2, color = nut_trt, fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(nut_trt)),
             geom = "polygon",
             fill = NA,  # Makes the ellipse transparent inside
             size = 1) +
  labs(title = "Grouped by Nutrient Treatment & Year - Blocks") +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

All years - LOW GRAZING ONLY

Stress: fair

0.1869068

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.low <- matrix0 %>%
  filter(grazing_hist == "low")

row.low <- paste(matrix.low$nut_trt, matrix.low$ppt_trt, matrix.low$yr, matrix.low$grazing_hist, sep = "_")

matrix.low <- matrix.low[, c(5:79)]

rownames(matrix.low) <- row.low
Warning: Setting row names on a tibble is deprecated.
matrix.bray.low <- decostand(matrix.low, "total")

metaMDS()

nmds.comp.low <- metaMDS(matrix.bray.low, k=2, trymax = 25)
Run 0 stress 0.2000574 
Run 1 stress 0.1960027 
... New best solution
... Procrustes: rmse 0.03759248  max resid 0.136796 
Run 2 stress 0.2299212 
Run 3 stress 0.1908791 
... New best solution
... Procrustes: rmse 0.1110161  max resid 0.2532458 
Run 4 stress 0.1869068 
... New best solution
... Procrustes: rmse 0.1544638  max resid 0.4035849 
Run 5 stress 0.2066946 
Run 6 stress 0.1878648 
Run 7 stress 0.2004585 
Run 8 stress 0.1876855 
Run 9 stress 0.2113763 
Run 10 stress 0.2243075 
Run 11 stress 0.1964757 
Run 12 stress 0.1893384 
Run 13 stress 0.2100567 
Run 14 stress 0.2455646 
Run 15 stress 0.1930573 
Run 16 stress 0.2043372 
Run 17 stress 0.245567 
Run 18 stress 0.2240266 
Run 19 stress 0.1942011 
Run 20 stress 0.1893384 
Run 21 stress 0.2104986 
Run 22 stress 0.1960027 
Run 23 stress 0.22813 
Run 24 stress 0.2593359 
Run 25 stress 0.1908791 
*** Best solution was not repeated -- monoMDS stopping criteria:
    23: stress ratio > sratmax
     2: scale factor of the gradient < sfgrmin
nmds.comp.low # pretty not great stress

Call:
metaMDS(comm = matrix.bray.low, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.low 
Distance: bray 

Dimensions: 2 
Stress:     0.1869068 
Stress type 1, weak ties
Best solution was not repeated after 25 tries
The best solution was from try 4 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.low’ 
stressplot(nmds.comp.low)

plot(nmds.comp.low, type="t")


nmds1 <- as.data.frame(scores(nmds.comp.low, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.low), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.low), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.low), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.low), "_"), `[`, 4)
  )
nmds2 <- as.data.frame(scores(nmds.comp.low, choices=c(2), display=c("sites")))

nmds_low_dat <- cbind(nmds1, nmds2) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)

plot

ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  color = as.factor(yr), shape = nut_trt)) +
  geom_point(size = 3, stroke = 1) + 
  labs(title = "2019-2021 (LOW) - Grouping by Year & Nutrient Treatment")


ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  labs(title = "2019-2021 (LOW) - Grouping by Nutrient Treatment")+ 
  custom_colors



ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2019-2021 (LOW) - Grouping by Precipitation Treatment") 


# add year ellipses ---- 
ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  labs(title = "2019-2021 (LOW) - Grouping by Nutrient Treatment")+ 
  custom_colors



ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
    stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  custom_colors + 
  labs(title = "2019-2021 (LOW) - Grouping by Precipitation Treatment") 

Make each individual year NMDS to see if there’s better stress

2019

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2019 <- matrix0 %>%
  filter(yr == 2019)

row.2019 <- paste(matrix.2019$nut_trt, matrix.2019$ppt_trt, matrix.2019$yr, matrix.2019$grazing_hist, sep = "_")

matrix.2019 <- matrix.2019[, c(5:79)]

rownames(matrix.2019) <- row.2019
Warning: Setting row names on a tibble is deprecated.
matrix.bray.2019 <- decostand(matrix.2019, "total")

nmds 2019

Stress: Excellent

0.0560178
metaMDS()
nmds.2019 <- metaMDS(matrix.bray.2019, k=2, trymax = 25)
Run 0 stress 0.0560178 
Run 1 stress 0.06223133 
Run 2 stress 0.05984339 
Run 3 stress 0.05905532 
Run 4 stress 0.06384512 
Run 5 stress 0.05851802 
Run 6 stress 0.05852022 
Run 7 stress 0.06942148 
Run 8 stress 0.05654879 
Run 9 stress 0.06942148 
Run 10 stress 0.05654879 
Run 11 stress 0.05877078 
Run 12 stress 0.0662005 
Run 13 stress 0.05982901 
Run 14 stress 0.05957995 
Run 15 stress 0.07018407 
Run 16 stress 0.05652852 
Run 17 stress 0.06074817 
Run 18 stress 0.05652852 
Run 19 stress 0.05654879 
Run 20 stress 0.07335647 
Run 21 stress 0.05851807 
Run 22 stress 0.05652852 
Run 23 stress 0.0735608 
Run 24 stress 0.0761203 
Run 25 stress 0.06228134 
*** Best solution was not repeated -- monoMDS stopping criteria:
    13: stress ratio > sratmax
    12: scale factor of the gradient < sfgrmin
nmds.2019 # pretty not great stress

Call:
metaMDS(comm = matrix.bray.2019, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2019 
Distance: bray 

Dimensions: 2 
Stress:     0.0560178 
Stress type 1, weak ties
Best solution was not repeated after 25 tries
The best solution was from try 0 (metric scaling or null solution)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2019’ 
stressplot(nmds.2019)

plot(nmds.2019, type="t")


nmds1.2019 <- as.data.frame(scores(nmds.2019, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 4)
  )
nmds2.2019 <- as.data.frame(scores(nmds.2019, choices=c(2), display=c("sites")))

nmds_2019_dat <- cbind(nmds1.2019, nmds2.2019) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_2019_dat, aes(NMDS1, NMDS2,  color = grazing_hist, shape = nut_trt)) +
  geom_point(size = 3, stroke = 1) + 
  labs(title = "2019 - Grouping by Grazing History & Nutrient Treatment")


ggplot(nmds_2019_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  labs(title = "2019 - Grouping by Nutrient Treatment")+ 
  custom_colors



ggplot(nmds_2019_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2019 - Grouping by Precipitation Treatment") 

2020

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2020 <- matrix0 %>%
  filter(yr == 2020)

row.2020 <- paste(matrix.2020$nut_trt, matrix.2020$ppt_trt, matrix.2020$yr, matrix.2020$grazing_hist, sep = "_")

matrix.2020 <- matrix.2020[, c(5:79)]

rownames(matrix.2020) <- row.2020
Warning: Setting row names on a tibble is deprecated.
matrix.bray.2020 <- decostand(matrix.2020, "total")

nmds 2020

Stress: fair

0.1522495
metaMDS()
nmds.2020 <- metaMDS(matrix.bray.2020, k=2, trymax = 25)
Run 0 stress 0.1524241 
Run 1 stress 0.1584809 
Run 2 stress 0.1584809 
Run 3 stress 0.1688381 
Run 4 stress 0.1625903 
Run 5 stress 0.153917 
Run 6 stress 0.3515938 
Run 7 stress 0.1692911 
Run 8 stress 0.1692911 
Run 9 stress 0.1584809 
Run 10 stress 0.1522495 
... New best solution
... Procrustes: rmse 0.02107749  max resid 0.06346372 
Run 11 stress 0.1584809 
Run 12 stress 0.1522045 
... New best solution
... Procrustes: rmse 0.01183105  max resid 0.0373035 
Run 13 stress 0.1744238 
Run 14 stress 0.1524241 
... Procrustes: rmse 0.02481397  max resid 0.06599247 
Run 15 stress 0.1742461 
Run 16 stress 0.1595062 
Run 17 stress 0.1524241 
... Procrustes: rmse 0.02481007  max resid 0.06599555 
Run 18 stress 0.1625903 
Run 19 stress 0.1522495 
... Procrustes: rmse 0.01183378  max resid 0.03737577 
Run 20 stress 0.1522495 
... Procrustes: rmse 0.0118299  max resid 0.03737025 
Run 21 stress 0.1747777 
Run 22 stress 0.184858 
Run 23 stress 0.1524241 
... Procrustes: rmse 0.02481216  max resid 0.06599381 
Run 24 stress 0.1866314 
Run 25 stress 0.2912948 
*** Best solution was not repeated -- monoMDS stopping criteria:
    20: stress ratio > sratmax
     5: scale factor of the gradient < sfgrmin
nmds.2020

Call:
metaMDS(comm = matrix.bray.2020, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2020 
Distance: bray 

Dimensions: 2 
Stress:     0.1522045 
Stress type 1, weak ties
Best solution was not repeated after 25 tries
The best solution was from try 12 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2020’ 
stressplot(nmds.2020)

plot(nmds.2020, type="t")


nmds1.2020 <- as.data.frame(scores(nmds.2020, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 4)
  )
nmds2.2020 <- as.data.frame(scores(nmds.2020, choices=c(2), display=c("sites")))

nmds_2020_dat <- cbind(nmds1.2020, nmds2.2020) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_2020_dat, aes(NMDS1, NMDS2,  color = grazing_hist, shape = nut_trt)) +
  geom_point(size = 4, stroke = 1) + 
  labs(title = "2020 - Grouping by Grazing History & Nutrient Treatment") 


ggplot(nmds_2020_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2020 - Grouping by Nutrient Treatment")


ggplot(nmds_2020_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2020 - Grouping by Precipitation Treatment")

2021

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2021 <- matrix0 %>%
  filter(yr == 2021)

row.2021 <- paste(matrix.2021$nut_trt, matrix.2021$ppt_trt, matrix.2021$yr, matrix.2021$grazing_hist, sep = "_")

matrix.2021 <- matrix.2021[, c(5:79)]

rownames(matrix.2021) <- row.2021
Warning: Setting row names on a tibble is deprecated.
matrix.bray.2021 <- decostand(matrix.2021, "total")
2021 - LOW

Stress

0.08067789
# relativize data with Bray-Curtis dissimilarity
matrix.2021.1 <- matrix0 %>%
  filter(yr == 2021,
         grazing_hist == "low") 

row.2021.1 <- paste(matrix.2021.1$nut_trt, matrix.2021.1$ppt_trt, matrix.2021.1$yr, matrix.2021.1$grazing_hist, sep = "_")

matrix.2021.1 <- matrix.2021.1[, c(5:79)]

rownames(matrix.2021.1) <- row.2021.1
Warning: Setting row names on a tibble is deprecated.
matrix.bray.2021.1 <- decostand(matrix.2021.1, "total")
nmds.2021.1 <- metaMDS(matrix.bray.2021.1, k=2, trymax = 25)
Run 0 stress 0.08067789 
Run 1 stress 0.1407365 
Run 2 stress 0.131677 
Run 3 stress 0.08067789 
... New best solution
... Procrustes: rmse 4.448434e-06  max resid 7.224535e-06 
... Similar to previous best
Run 4 stress 0.1393679 
Run 5 stress 0.08067789 
... New best solution
... Procrustes: rmse 1.053765e-06  max resid 1.585547e-06 
... Similar to previous best
Run 6 stress 0.1393365 
Run 7 stress 0.1393365 
Run 8 stress 0.08067789 
... Procrustes: rmse 5.054553e-06  max resid 8.236855e-06 
... Similar to previous best
Run 9 stress 0.08067789 
... Procrustes: rmse 5.780641e-06  max resid 8.023545e-06 
... Similar to previous best
Run 10 stress 0.08067789 
... Procrustes: rmse 4.42502e-06  max resid 6.754172e-06 
... Similar to previous best
Run 11 stress 0.2039408 
Run 12 stress 0.08067789 
... Procrustes: rmse 1.729526e-06  max resid 2.63632e-06 
... Similar to previous best
Run 13 stress 0.08067789 
... New best solution
... Procrustes: rmse 1.098472e-06  max resid 1.772254e-06 
... Similar to previous best
Run 14 stress 0.1316771 
Run 15 stress 0.2639821 
Run 16 stress 0.203941 
Run 17 stress 0.08067789 
... Procrustes: rmse 3.956956e-06  max resid 5.336733e-06 
... Similar to previous best
Run 18 stress 0.08067789 
... Procrustes: rmse 1.630904e-06  max resid 3.249717e-06 
... Similar to previous best
Run 19 stress 0.1203381 
Run 20 stress 0.2039414 
*** Best solution repeated 3 times
nmds.2021.1

Call:
metaMDS(comm = matrix.bray.2021.1, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2021.1 
Distance: bray 

Dimensions: 2 
Stress:     0.08067789 
Stress type 1, weak ties
Best solution was repeated 3 times in 20 tries
The best solution was from try 13 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2021.1’ 
stressplot(nmds.2021.1)

plot(nmds.2021.1, type="t")

dummy <- as.data.frame(scores(nmds.2021.1, choices=c(1), display=c("sites")))

nmds1.2021.1.df <- as.data.frame(scores(nmds.2021.1, choices=c(1), display=c("sites"))) %>%
  mutate(trt = rownames(dummy)) %>%
  separate(trt, c("nut_trt", "ppt_trt", "pr", "grazing_hist"), sep="_")

nmds2.2021.1 <- as.data.frame(scores(nmds.2021.1, choices=c(2), display=c("sites")))

nmds_2021_dat.1 <- cbind(nmds1.2021.1.df, nmds2.2021.1) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
# ggplot(nmds_2021_dat.1, aes(NMDS1, NMDS2,  color = grazing_hist, shape = nut_trt)) +
#   geom_point(size = 4, stroke = 0.5) +
#   labs(title = "2021 - Grouping by Grazing History & Nutrient Treatment")

ggplot(nmds_2021_dat.1, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (LOW) - Grouping by Nutrient Treatment")


ggplot(nmds_2021_dat.1, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (LOW) - Grouping by Precipitation Treatment")

2021 - HIGH

Stress

0.08065034
# relativize data with Bray-Curtis dissimilarity
matrix.2021.2 <- matrix0 %>%
  filter(yr == 2021,
         grazing_hist == "high") 

row.2021.2 <- paste(matrix.2021.2$nut_trt, matrix.2021.2$ppt_trt, matrix.2021.2$yr, matrix.2021.2$grazing_hist, sep = "_")

matrix.2021.2 <- matrix.2021.2[, c(5:79)]

rownames(matrix.2021.2) <- row.2021.2
Warning: Setting row names on a tibble is deprecated.
matrix.bray.2021.2 <- decostand(matrix.2021.2, "total")
nmds.2021.2 <- metaMDS(matrix.bray.2021.2, k=2, trymax = 25)
Run 0 stress 0.08065034 
Run 1 stress 0.1378308 
Run 2 stress 0.08065034 
... Procrustes: rmse 2.805412e-05  max resid 5.594612e-05 
... Similar to previous best
Run 3 stress 0.1378308 
Run 4 stress 0.08065035 
... Procrustes: rmse 7.802029e-05  max resid 0.0001548812 
... Similar to previous best
Run 5 stress 0.08065034 
... Procrustes: rmse 3.731121e-05  max resid 6.566436e-05 
... Similar to previous best
Run 6 stress 0.1378308 
Run 7 stress 0.08554815 
Run 8 stress 0.08065037 
... Procrustes: rmse 0.0001137107  max resid 0.0002575052 
... Similar to previous best
Run 9 stress 0.08554815 
Run 10 stress 0.1378309 
Run 11 stress 0.08065034 
... New best solution
... Procrustes: rmse 1.388738e-05  max resid 1.990997e-05 
... Similar to previous best
Run 12 stress 0.1378309 
Run 13 stress 0.1905268 
Run 14 stress 0.1743257 
Run 15 stress 0.08065036 
... Procrustes: rmse 7.179091e-05  max resid 0.0001453003 
... Similar to previous best
Run 16 stress 0.08065034 
... Procrustes: rmse 4.443671e-05  max resid 7.380012e-05 
... Similar to previous best
Run 17 stress 0.08065034 
... Procrustes: rmse 9.112915e-06  max resid 1.854915e-05 
... Similar to previous best
Run 18 stress 0.08065035 
... Procrustes: rmse 4.869656e-05  max resid 9.470507e-05 
... Similar to previous best
Run 19 stress 0.1460913 
Run 20 stress 0.1378308 
*** Best solution repeated 5 times
nmds.2021.2

Call:
metaMDS(comm = matrix.bray.2021.2, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2021.2 
Distance: bray 

Dimensions: 2 
Stress:     0.08065034 
Stress type 1, weak ties
Best solution was repeated 5 times in 20 tries
The best solution was from try 11 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2021.2’ 
stressplot(nmds.2021.2)

plot(nmds.2021.2, type="t")

dummy <- as.data.frame(scores(nmds.2021.2, choices=c(1), display=c("sites")))

nmds1.2021.2.df <- as.data.frame(scores(nmds.2021.2, choices=c(1), display=c("sites"))) %>%
  mutate(trt = rownames(dummy)) %>%
  separate(trt, c("nut_trt", "ppt_trt", "pr", "grazing_hist"), sep="_")

nmds2.2021.2 <- as.data.frame(scores(nmds.2021.2, choices=c(2), display=c("sites")))

nmds_2021_dat.2 <- cbind(nmds1.2021.2.df, nmds2.2021.2) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
ggplot(nmds_2021_dat.2, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (HIGH) - Grouping by Nutrient Treatment")


ggplot(nmds_2021_dat.2, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (HIGH) - Grouping by Precipitation Treatment")

nmds 2021

Stress: fair

0.1230831
metaMDS()
nmds.2021 <- metaMDS(matrix.bray.2021, k=2, trymax = 25)
Run 0 stress 0.1232098 
Run 1 stress 0.1339879 
Run 2 stress 0.1230831 
... New best solution
... Procrustes: rmse 0.04463789  max resid 0.1321469 
Run 3 stress 0.1230831 
... Procrustes: rmse 1.350077e-05  max resid 4.219102e-05 
... Similar to previous best
Run 4 stress 0.133988 
Run 5 stress 0.1507047 
Run 6 stress 0.1573377 
Run 7 stress 0.1230831 
... Procrustes: rmse 2.810056e-06  max resid 8.291934e-06 
... Similar to previous best
Run 8 stress 0.1339879 
Run 9 stress 0.1230831 
... Procrustes: rmse 8.646086e-06  max resid 2.745517e-05 
... Similar to previous best
Run 10 stress 0.132972 
Run 11 stress 0.1232098 
... Procrustes: rmse 0.04463824  max resid 0.1315186 
Run 12 stress 0.1230831 
... New best solution
... Procrustes: rmse 2.871318e-06  max resid 7.467703e-06 
... Similar to previous best
Run 13 stress 0.1421227 
Run 14 stress 0.1232098 
... Procrustes: rmse 0.04463976  max resid 0.1315202 
Run 15 stress 0.1339879 
Run 16 stress 0.1515614 
Run 17 stress 0.1230832 
... Procrustes: rmse 2.468942e-05  max resid 7.756011e-05 
... Similar to previous best
Run 18 stress 0.1573377 
Run 19 stress 0.1230831 
... Procrustes: rmse 7.42768e-06  max resid 2.388952e-05 
... Similar to previous best
Run 20 stress 0.132972 
*** Best solution repeated 3 times
nmds.2021

Call:
metaMDS(comm = matrix.bray.2021, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2021 
Distance: bray 

Dimensions: 2 
Stress:     0.1230831 
Stress type 1, weak ties
Best solution was repeated 3 times in 20 tries
The best solution was from try 12 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2021’ 
stressplot(nmds.2021)

plot(nmds.2021, type="t")


nmds1.2021 <- as.data.frame(scores(nmds.2021, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 4)
  )
nmds2.2021 <- as.data.frame(scores(nmds.2021, choices=c(2), display=c("sites")))

nmds_2021_dat <- cbind(nmds1.2021, nmds2.2021) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_2021_dat, aes(NMDS1, NMDS2,  color = grazing_hist, shape = nut_trt)) +
  geom_point(size = 4, stroke = 0.5) +
  labs(title = "2021 - Grouping by Grazing History & Nutrient Treatment")


ggplot(nmds_2021_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 - Grouping by Nutrient Treatment")


ggplot(nmds_2021_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 - Grouping by Precipitation Treatment")

2021 — blocks

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2021.block <- matrix0.block %>%
  filter(yr == 2021)

row.2021.block <- paste(matrix.2021.block$nut_trt, matrix.2021.block$ppt_trt, matrix.2021.block$yr, matrix.2021.block$block, sep = "_")

matrix.2021.block <- matrix.2021.block[, c(5:79)]

rownames(matrix.2021.block) <- row.2021.block
Warning: Setting row names on a tibble is deprecated.
matrix.bray.block.2021 <- decostand(matrix.2021.block, "total")

nmds 2021

Stress: fair

0.1702944
metaMDS()
nmds.2021.block <- metaMDS(matrix.bray.block.2021, k=2, trymax = 25)
Run 0 stress 0.1702944 
Run 1 stress 0.2323726 
Run 2 stress 0.2333131 
Run 3 stress 0.1702944 
... New best solution
... Procrustes: rmse 8.12052e-06  max resid 2.925004e-05 
... Similar to previous best
Run 4 stress 0.1704654 
... Procrustes: rmse 0.006480506  max resid 0.02760662 
Run 5 stress 0.2085283 
Run 6 stress 0.2044772 
Run 7 stress 0.2146073 
Run 8 stress 0.1942847 
Run 9 stress 0.1873962 
Run 10 stress 0.2098049 
Run 11 stress 0.1917675 
Run 12 stress 0.1833145 
Run 13 stress 0.2044772 
Run 14 stress 0.226506 
Run 15 stress 0.2142311 
Run 16 stress 0.1702944 
... Procrustes: rmse 5.781581e-06  max resid 1.825294e-05 
... Similar to previous best
Run 17 stress 0.1798315 
Run 18 stress 0.1704654 
... Procrustes: rmse 0.006481124  max resid 0.02760841 
Run 19 stress 0.2355275 
Run 20 stress 0.2089454 
*** Best solution repeated 2 times
nmds.2021.block

Call:
metaMDS(comm = matrix.bray.block.2021, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.block.2021 
Distance: bray 

Dimensions: 2 
Stress:     0.1702944 
Stress type 1, weak ties
Best solution was repeated 2 times in 20 tries
The best solution was from try 3 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.block.2021’ 
stressplot(nmds.2021.block)

plot(nmds.2021.block, type="t")


nmds1.2021.block <- as.data.frame(scores(nmds.2021.block, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2021.block), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2021.block), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2021.block), "_"), `[`, 3),
    block = sapply(strsplit(rownames(matrix.2021.block), "_"), `[`, 4)
  )
nmds2.2021.block <- as.data.frame(scores(nmds.2021.block, choices=c(2), display=c("sites")))

nmds_2021_dat.block <- cbind(nmds1.2021.block, nmds2.2021.block) %>%
  select(nut_trt:block, NMDS1, NMDS2)
plot
ggplot(nmds_2021_dat.block, aes(NMDS1, NMDS2,  color = block, shape = nut_trt)) +
  geom_point(size = 4, stroke = 0.5) +
  labs(title = "2021 (Block) - Grouping by Block & Nutrient Treatment")


ggplot(nmds_2021_dat.block, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block) - Grouping by Nutrient Treatment")


ggplot(nmds_2021_dat.block, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block) - Grouping by Precipitation Treatment")

2021 — blocks (LOW)

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2021.block.low <- matrix0.block %>%
  filter(yr == 2021,
         block == 3 | block == 4)

row.2021.block.low <- paste(matrix.2021.block.low$nut_trt, matrix.2021.block.low$ppt_trt, matrix.2021.block.low$yr, matrix.2021.block.low$block, sep = "_")

matrix.2021.block.low <- matrix.2021.block.low[, -c(0:4)]

rownames(matrix.2021.block.low) <- row.2021.block.low
Warning: Setting row names on a tibble is deprecated.
matrix.bray.block.2021.low <- decostand(matrix.2021.block.low, "total")

nmds 2021

Stress: fair

0.1282296
metaMDS()
nmds.2021.block.low <- metaMDS(matrix.bray.block.2021.low, k=2, trymax = 25)
Run 0 stress 0.1282296 
Run 1 stress 0.1282296 
... New best solution
... Procrustes: rmse 6.900845e-05  max resid 0.0001846812 
... Similar to previous best
Run 2 stress 0.1282296 
... New best solution
... Procrustes: rmse 6.471065e-05  max resid 0.0002196127 
... Similar to previous best
Run 3 stress 0.1282296 
... Procrustes: rmse 8.428118e-05  max resid 0.0003017723 
... Similar to previous best
Run 4 stress 0.1985506 
Run 5 stress 0.1282296 
... Procrustes: rmse 1.033532e-05  max resid 2.797048e-05 
... Similar to previous best
Run 6 stress 0.1785638 
Run 7 stress 0.1282296 
... Procrustes: rmse 8.012815e-05  max resid 0.0002839093 
... Similar to previous best
Run 8 stress 0.1282296 
... Procrustes: rmse 5.434575e-05  max resid 0.0001894526 
... Similar to previous best
Run 9 stress 0.1282296 
... New best solution
... Procrustes: rmse 1.600545e-05  max resid 5.619322e-05 
... Similar to previous best
Run 10 stress 0.1282296 
... Procrustes: rmse 1.523127e-05  max resid 5.391544e-05 
... Similar to previous best
Run 11 stress 0.1428149 
Run 12 stress 0.1627541 
Run 13 stress 0.2101121 
Run 14 stress 0.1282296 
... Procrustes: rmse 2.043501e-05  max resid 6.96312e-05 
... Similar to previous best
Run 15 stress 0.2053314 
Run 16 stress 0.2106634 
Run 17 stress 0.1282296 
... Procrustes: rmse 8.924757e-05  max resid 0.0003091915 
... Similar to previous best
Run 18 stress 0.1428149 
Run 19 stress 0.1428149 
Run 20 stress 0.1428149 
*** Best solution repeated 4 times
nmds.2021.block.low

Call:
metaMDS(comm = matrix.bray.block.2021.low, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.block.2021.low 
Distance: bray 

Dimensions: 2 
Stress:     0.1282296 
Stress type 1, weak ties
Best solution was repeated 4 times in 20 tries
The best solution was from try 9 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.block.2021.low’ 
stressplot(nmds.2021.block.low)

plot(nmds.2021.block.low, type="t")


nmds1.2021.block.low <- as.data.frame(scores(nmds.2021.block.low, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2021.block.low), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2021.block.low), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2021.block.low), "_"), `[`, 3),
    block = sapply(strsplit(rownames(matrix.2021.block.low), "_"), `[`, 4)
  )
nmds2.2021.block.low <- as.data.frame(scores(nmds.2021.block.low, choices=c(2), display=c("sites")))

nmds_2021_dat.block.low <- cbind(nmds1.2021.block.low, nmds2.2021.block.low) %>%
  select(nut_trt:block, NMDS1, NMDS2)
plot
ggplot(nmds_2021_dat.block.low, aes(NMDS1, NMDS2,  color = block, shape = nut_trt)) +
  geom_point(size = 4, stroke = 0.5) +
  labs(title = "2021 (Block; LOW) - Grouping by Block & Nutrient Treatment")


ggplot(nmds_2021_dat.block.low, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; LOW) - Grouping by Nutrient Treatment")


ggplot(nmds_2021_dat.block.low, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; LOW) - Grouping by Precipitation Treatment")

2021 — blocks (HIGH)

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2021.block.high <- matrix0.block %>%
  filter(yr == 2021,
         block == 1 | block == 2)

row.2021.block.high <- paste(matrix.2021.block.high$nut_trt, matrix.2021.block.high$ppt_trt, matrix.2021.block.high$yr, matrix.2021.block.high$block, sep = "_")

matrix.2021.block.high <- matrix.2021.block.high[, -c(0:4)]

rownames(matrix.2021.block.high) <- row.2021.block.high
Warning: Setting row names on a tibble is deprecated.
matrix.bray.block.2021.high <- decostand(matrix.2021.block.high, "total")

nmds 2021

Stress: fair

0.1412997
metaMDS()
nmds.2021.block.high <- metaMDS(matrix.bray.block.2021.high, k=2, trymax = 25)
Run 0 stress 0.1412997 
Run 1 stress 0.1430823 
Run 2 stress 0.1430824 
Run 3 stress 0.1856239 
Run 4 stress 0.1581575 
Run 5 stress 0.1412999 
... Procrustes: rmse 0.0003384719  max resid 0.001097121 
... Similar to previous best
Run 6 stress 0.1430825 
Run 7 stress 0.1581574 
Run 8 stress 0.1856239 
Run 9 stress 0.1412997 
... Procrustes: rmse 3.643604e-05  max resid 0.0001217465 
... Similar to previous best
Run 10 stress 0.1581574 
Run 11 stress 0.1581574 
Run 12 stress 0.1430824 
Run 13 stress 0.1430824 
Run 14 stress 0.1581574 
Run 15 stress 0.2412356 
Run 16 stress 0.1430827 
Run 17 stress 0.1430824 
Run 18 stress 0.1412998 
... Procrustes: rmse 0.0002267585  max resid 0.0007337562 
... Similar to previous best
Run 19 stress 0.1581575 
Run 20 stress 0.1581574 
*** Best solution repeated 3 times
nmds.2021.block.high

Call:
metaMDS(comm = matrix.bray.block.2021.high, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.block.2021.high 
Distance: bray 

Dimensions: 2 
Stress:     0.1412997 
Stress type 1, weak ties
Best solution was repeated 3 times in 20 tries
The best solution was from try 0 (metric scaling or null solution)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.block.2021.high’ 
stressplot(nmds.2021.block.high)

plot(nmds.2021.block.high, type="t")


nmds1.2021.block.high <- as.data.frame(scores(nmds.2021.block.high, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2021.block.high), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2021.block.high), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2021.block.high), "_"), `[`, 3),
    block = sapply(strsplit(rownames(matrix.2021.block.high), "_"), `[`, 4)
  )
nmds2.2021.block.high <- as.data.frame(scores(nmds.2021.block.high, choices=c(2), display=c("sites")))

nmds_2021_dat.block.high <- cbind(nmds1.2021.block.high, nmds2.2021.block.high) %>%
  select(nut_trt:block, NMDS1, NMDS2)
plot
ggplot(nmds_2021_dat.block.high, aes(NMDS1, NMDS2,  color = block, shape = nut_trt)) +
  geom_point(size = 4, stroke = 0.5) +
  labs(title = "2021 (Block; HIGH) - Grouping by Block & Nutrient Treatment")


ggplot(nmds_2021_dat.block.high, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; HIGH) - Grouping by Nutrient Treatment")


ggplot(nmds_2021_dat.block.high, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; HIGH) - Grouping by Precipitation Treatment")

Make species x trait matrix

Greenhouse traits

  • height, leaf dry matter content, specific leaf area, root mass fraction, relative growth rate, coarse root diameter, root density, specific root length of fine roots, specific root length of coarse roots

Field traits

  • height, leaf dry matter content, specific leaf area, seed mass, leaf C, leaf N

“H1: Pairing field results with a greenhouse 15 N experiment will allow us to relate species responses to their ability to uptake organic N”

“In addition, we will conduct a greenhouse experiment to isolate the mechanism (mineralized N vs organic N uptake rates ) by which compost may affect species composition”

Workflow plan:

  • overlay species trait data as vectors on the NMDS

    • only greenhouse traits available (only sla data from field)

      • use PC scores as composite trait axes OR

      • average the traits for each species

Read in trait data

# # read in greenhouse trait data
# traits.gh <- read.csv("https://www.dropbox.com/scl/fi/c8vk31a807xg48jez1j03/GreenhouseTraits.csv?rlkey=ca736ea27k79mo7h8dbn67qiq&st=ya1ck6p7&dl=1")
# 
# # read in field trait data
# # download.file("https://www.dropbox.com/scl/fi/trqrnz54dkjoa9do4tle5/leaf-area-data_NG.xlsx?rlkey=s0kic2a5yqknikc4icek8y7rn&st=dl4x634h&dl=1",destfile = "field_sla.xlsx")
# traits.sla.field <- 
#   read_excel("field_sla.xlsx",col_names = TRUE,col_types = "text")
# 
# rda(traits.gh, scale = TRUE)

Investigate trait data, looking in Greenhouse trait folder

Trait data is identical. Will clean data in

# dropbox.main <- read.csv("https://www.dropbox.com/scl/fi/c8vk31a807xg48jez1j03/GreenhouseTraits.csv?rlkey=ca736ea27k79mo7h8dbn67qiq&st=0h1bs53j&dl=1")
# 
# dropbox.gh <- read.csv("https://www.dropbox.com/scl/fi/67aaubdydiy4ixffmwvfe/GreenhouseTraits.csv?rlkey=rm2eqeqome7hgoedhnal0gx6d&st=vkym6evx&dl=1")
# 
# all.equal(dropbox.main, dropbox.gh)
# identical(dropbox.main, dropbox.gh)
traits.cleaned <- read.csv("data/GreenhouseTraits_corrected_20240212.csv") %>%
  mutate(
    Fresh.leaf.mass..g. = as.numeric(ifelse(
      Fresh.leaf.mass..g. == "Skipped accidentally", NA, Fresh.leaf.mass..g.
    )),
    Dry.leaf.mass..g. = as.numeric(ifelse(
      Dry.leaf.mass..g. == "No sample", NA, Dry.leaf.mass..g.
    )),
    Root.dry.biomass..g. = as.numeric(ifelse(
      Root.dry.biomass..g. == "roots lost", NA, Root.dry.biomass..g.
    )),
    Root.volume..cm3. = as.numeric(ifelse(
      Root.volume..cm3. == "not scanned", NA, Root.volume..cm3.
    ))
  ) 
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `Root.dry.biomass..g. = as.numeric(ifelse(Root.dry.biomass..g. == "roots lost", NA,
  Root.dry.biomass..g.))`.
Caused by warning:
! NAs introduced by coercion

Summarize trait data (GH) for each species

means

# make trait species ID match matrix data (notes shown below) -------
traits.cleaned <- traits.cleaned %>%
  mutate(
    ID = ifelse(
      ID == "Agoseris", "AGSP", ifelse(
        ID == "AVEBAR", "AVBA", ifelse(
          ID == "BRDR", "BRDI", ID
        )
      )
    )
  )

# summary(traits.cleaned)
traits.means <- traits.cleaned %>%
  group_by(ID) %>%
  summarise(
    across(4:(ncol(traits.gh) - 1), list(mean = ~mean(.x, na.rm = TRUE)
  )))
  

# make site by species matrix match traits species
matrix.names <- data.frame(colnames(matrix.bray)) #species comp (75 count)
trait.names <- data.frame(traits.means$ID) #trait species (80 count)

intersect.names <- intersect(colnames(matrix.bray), traits.means$ID) # same species (43 count)
setdiff(colnames(matrix.bray), traits.means$ID)
 [1] "ASSP"  "AST1"  "AST2"  "AST3"  "CIQU"  "CRTI"  "CYEC"  "DACA"  "DIMU"  "GAGR"  "GAPA"  "GAPH"  "HYSP" 
[14] "JUBU"  "LYHY"  "MAD1"  "MAD2"  "NAPU"  "PAVI"  "SABI1" "SABI2" "SIGA"  "THGR"  "TRSP"  "UNBU"  "UNF1" 
[27] "UNF3"  "UNF4"  "UNF8"  "UNFR"  "UNGR"  "XAST" 
setdiff(traits.means$ID, colnames(matrix.bray))
 [1] "ACMI"      "ANARp"     "AVFA"      "BRCA"      "BRHOp"     "BRNIf"     "BRNIp"     "CLPUf"     "CLPUp"    
[10] "CYDA"      "Crassula"  "ESCA"      "FEMI"      "FEMY"      "GITRf"     "GITRp"     "HYGL"      "LACA"     
[19] "LENIf"     "LENIp"     "LOPU"      "LUBI"      "Leontodon" "MAELf"     "MAELp"     "MICA"      "NEMA"     
[28] "PLERf"     "PLERp"     "RUPU"      "Sanicula"  "TRCI"      "TRHIpi"    "TRWIf"     "TRWIp"     "TRWIpi"   
[37] "VIVA"     
# check matrix codes to see if same species are named different things
unique.matrix.species <- cover.dat %>%
  dplyr::select(code4, species) %>%
  summarise(
    code4 = unique(code4),
    species = unique(species)
  )
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
unique.trait.species <- traits.cleaned %>%
  dplyr::select(Taxon, ID) %>%
  distinct(ID, .keep_all = TRUE)
  
  • change Trait name: ‘Agoseris’ –> ‘Agoseris unknown’; assuming the same as ‘AGSP’ –> ‘Agoseris sp.’ in matrix data (change to matrix name)

  • What’s the difference between:

    • ‘ANAR’ and ‘ANARp’ in trait data?

    • ‘BRHO’ and ‘BRHOp’ in trait data?

    • ‘BRNIf’ and ‘BRNIp’ in trait data? (not in matrix data)

    • ‘CLPUf’ and ‘CLPUp’ in trait data? (not in matrix data)

    • ‘GITRf’ and ‘GITRp’ in trait data? (not in matrix data)

    • ‘LENIf’ and ‘LENIp’ in trait data? (not in matrix data)

    • ‘TRHI’ and ‘TRHIpi’ (same sp name) in trait data? (TRHI in matrix data)

    • ‘TRWIf’ and ‘TRWIp’ and ‘TRWIpi’ in trait data? (not in matrix data)

    • ‘Crassula’ and ‘Crassula tillaea’ (could they be the same?)

    • ‘Sanicula’ (unknown) and ‘SABI1’ or ‘SABI2’ (could they be the same?)

    • ‘MAELf’ (trait data) and ‘MAD1’ (Madia sp. 1 (“tall tarweed”)’ (could they be the same?)

    • ‘MAELp’ (trait data) and ‘MAD2’ (Madia sp. 1 (“small tarweed”)’ (could they be the same?)

    • ‘Trifolium eriocephalum’ (TRER) and ‘Triphysaria eriantha’ (TRER) (could they be the same?)

  • change ‘AVEBAR’ (trait data) to ‘AVBA’ (matrix data)

  • change BRDR –> BRDI

Overlay Trait Vectors onto NMDS

ALL YEARS – LOW AND HIGH GRAZING

Prepare NMDS and Traits

Stress:

0.2011127
# subset nmds to match species names
nmds.comp.trait <- metaMDS(matrix.bray %>%
                             dplyr::select(intersect.names), 
                           k=2, trymax = 25)
Run 0 stress 0.2060005 
Run 1 stress 0.2007525 
... New best solution
... Procrustes: rmse 0.06486829  max resid 0.1521338 
Run 2 stress 0.2133228 
Run 3 stress 0.2079153 
Run 4 stress 0.2051687 
Run 5 stress 0.2107849 
Run 6 stress 0.2078775 
Run 7 stress 0.2027188 
Run 8 stress 0.2013372 
Run 9 stress 0.2050098 
Run 10 stress 0.2017137 
Run 11 stress 0.2042866 
Run 12 stress 0.2051682 
Run 13 stress 0.2185014 
Run 14 stress 0.2078775 
Run 15 stress 0.2156872 
Run 16 stress 0.2221242 
Run 17 stress 0.2079153 
Run 18 stress 0.2023083 
Run 19 stress 0.2181406 
Run 20 stress 0.2010909 
... Procrustes: rmse 0.08100757  max resid 0.2166622 
Run 21 stress 0.2086475 
Run 22 stress 0.2046958 
Run 23 stress 0.2061378 
Run 24 stress 0.2020872 
Run 25 stress 0.2080994 
*** Best solution was not repeated -- monoMDS stopping criteria:
    24: stress ratio > sratmax
     1: scale factor of the gradient < sfgrmin
nmds.comp.trait # pretty not great stress

Call:
metaMDS(comm = matrix.bray %>% dplyr::select(intersect.names),      k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray %>% dplyr::select(intersect.names) 
Distance: bray 

Dimensions: 2 
Stress:     0.2007525 
Stress type 1, weak ties
Best solution was not repeated after 25 tries
The best solution was from try 1 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray %>% dplyr::select(intersect.names)’ 
stressplot(nmds.comp.trait)

plot(nmds.comp.trait, type="t")


nmds1 <- as.data.frame(scores(nmds.comp.trait, choices=c(1), display=c("sites")))
nmds2 <- as.data.frame(scores(nmds.comp.trait, choices=c(2), display=c("sites")))

nmds_dat_trait <- cbind(nmds1, nmds2) %>%
  as.data.frame() %>%  # Ensure it's a data frame
  rownames_to_column(var = "site_id") %>%  # Move row names into a new column
  separate(site_id, into = c("nut_trt", "ppt_trt", "yr", "grazing_hist"), sep = "_")


# subset matrix and trait data to match names
traits.means.comp <- traits.means %>%
  filter(ID %in% intersect.names) %>%
  rename(
    Height = Height..cm._mean,
    FreshLeafMass = Fresh.leaf.mass..g._mean,
    DryLeafMass = Dry.leaf.mass..g._mean,
    LDMC = LDMC_mean, # Leaf dry matter content (LDMC, the ratio of leaf dry mass to fresh mass)
    LeafArea = Leaf.Area..cm2._mean,
    SLA = SLA..cm2.g._mean,
    ShootDryBiomass = Shoot.dry.biomass..g._mean,
    RootDryBiomass = Root.dry.biomass..g._mean,
    TotalBiomass = Total.biomass..g._mean,
    RMF = RMF_mean, # Root mass fraction (RMF) is a plant trait that measures the proportion of a plant's dry mass that is in its roots
    RootVol = Root.volume..cm3._mean,
    RootDensity = Root.density..g.cm3._mean,
    CoarseRootDiameter = Coarse.root.diameter..mm._mean,
    RootLength = Length..mm._mean,
    FineRootLength = Fine.root.length..mm._mean,
    CoarseRootLength = Coarse.root.length..mm._mean,
    CoarseRootSpecLength = Coarse.root.specific.length..cm.g._mean,
    FineRootSpecLength = Fine.root.specific.length..cm.g._mean,
    PropFineRoots = Proportion.fine.roots_mean
    
  )
# traits.means.comp2 <- traits.means.comp %>%
# dplyr::select(-ID)
rownames(traits.means.comp2) <- traits.means.comp$ID
Warning: Setting row names on a tibble is deprecated.
# trait vectors onto the NMDS
# envfit(nmds.comp.trait, traits.means.comp, permutations = 999)
# example from stack overflow: envfit(ord ~ var1 + var2 + var3, dune.spec, display="sp"), 'ord' is the nmds model, 'var1' is the trait1 i think?

colnames(traits.means.comp)
 [1] "ID"                   "Height"               "FreshLeafMass"        "DryLeafMass"         
 [5] "LDMC"                 "LeafArea"             "SLA"                  "ShootDryBiomass"     
 [9] "RootDryBiomass"       "TotalBiomass"         "RMF"                  "RootVol"             
[13] "RootDensity"          "CoarseRootDiameter"   "RootLength"           "FineRootLength"      
[17] "CoarseRootLength"     "CoarseRootSpecLength" "FineRootSpecLength"   "PropFineRoots"       
vectors.nmds.comp.trait <- envfit(nmds.comp.trait ~ Height + 
                                    LeafArea +
                                    RMF, traits.means.comp, display = "sp") # ONLY Height, Leaf area, and RMF significant

# is it different when you only do certain traits (above- vs. below-ground)? or can you just throw everything in there and it will tell you what is significant and you can subset from there?

# Looks like different subsets of traits put in are the same, so I shall proceed with the mega models and verify with Lauren

trait_vectors <- as.data.frame(vectors.nmds.comp.trait$vectors$arrows)

NMDS model: only Height, Leaf area, and RMF () found significant.

Plot

ggplot(nmds_dat_trait, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  # stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Nutrient Treatment") +
  custom_colors +
  scale_color_manual(
    values = c(
      "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
      "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
      "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
      "wet" = rgb(0, 0, 255, maxColorValue = 255),
      "dry" = rgb(183, 65, 14, maxColorValue = 255)
    )
  ) +
  geom_segment(
    data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
    aes(x = NMDS1, y = NMDS2, label = rownames(vectors.nmds.comp.trait$vectors$arrows)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )



ggplot(nmds_dat_trait, aes(NMDS1, NMDS2, color = as.factor(yr), fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Year")


ggplot(nmds_dat_trait, aes(NMDS1, NMDS2, fill = as.factor(ppt_trt), color = as.factor(ppt_trt))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Precipitation Treatment") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)


ggplot(nmds_dat_trait, aes(NMDS1, NMDS2,  fill = as.factor(grazing_hist), color = as.factor(grazing_hist))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Grazing History")


ggplot(nmds_dat_trait, aes(NMDS1, NMDS2,  color = as.factor(grazing_hist), fill = as.factor(yr))) +
  geom_point(aes(fill = as.factor(yr)), shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  labs(title = "Grouped by Grazing History & Year") +
  scale_color_manual(
  values = c(
    "low" = "cyan",
    "high" = "brown",
  "2019" = "salmon",
  "2020" = "limegreen",
  "2021" = "cornflowerblue")
  )

  
ggplot(nmds_dat_trait, aes(NMDS1, NMDS2, color = nut_trt, fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(nut_trt)),
             geom = "polygon",
             fill = NA,  # Makes the ellipse transparent inside
             size = 1) +
  labs(title = "Grouped by Nutrient Treatment & Year") +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

LS0tCnRpdGxlOiAiVHJhaXQgT3JkaW5hdGlvbiBQbGFudCBDb21tdW5pdHkgQW5hbHlzaXMiCmF1dGhvcjogIkNhcnluIEQuIEl3YW5hZ2EiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogeWVzCi0tLQoKIyBUcmFpdCBPcmRpbmF0aW9uIFBsYW50IENvbW11bml0eSBBbmFseXNpcwoKMS4gIHRyYWl0cwoKICAgIDEuICBhYm92ZS0gYW5kIGJlbG93Z3JvdW5kCgogICAgICAgIDEuICBoZWlnaHQgJiBTTEFcCgogICAgMi4gIGFjcXVpc2l0aXZlIHZzLiBjb25zZXJ2YXRpdmUgcmVzb3VyY2UtdXNlIHN0cmF0ZWdpZXMKCiAgICAgICAgMS4gIHJvb3RpbmcgZGVwdGgKCiAgICAzLiAgY29sbGFib3JhdGl2ZSB2cy4gaW5kaXZpZHVhbCByZXNvdXJjZS11c2Ugc3RyYXRlZ2llcwoKICAgICAgICAxLiAgZmluZSByb290IHByb3BvcnRpb24KCiAgICAgICAgMi4gIHRoaWNrbmVzcyBvZiByb290cwoKW0dvYWxdey51bmRlcmxpbmV9OiBFeGFtaW5lIGhvdyB0cmFpdHMgc2hpZnQgaW4gY29tbXVuaXR5IGNvbXBvc2l0aW9uYWwgKG9yZGluYXRpb25hbCkgc3BhY2UsIHBsYWNpbmcgZWFjaCB0cmFpdCBvbiBhbiBheGlzLgoKQXV0aG9yOiBDYXJ5biBELiBJd2FuYWdhCgpVcGRhdGVkOiAwMi8wNi8yMDI1CgojIyBMaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGh0dHIpICMgcmVhZCBvdXQgRHJvcGJveCBmb2xkZXJzCmxpYnJhcnkodmVnYW4pCmxpYnJhcnkocmVhZHhsKQpgYGAKCiMjIFJlYWQgaW4gRGF0YQoKYGBge3J9CmNvdmVyLmRhdC5sYWJlbHMgPC0gcmVhZC5jc3YoImh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3NjbC9maS91cDhubnprY3BjaHNyNDVmOGNtOTIvQ29tcG9zdF9Db3Zlcl9Mb25nQ2xlYW4uY3N2P3Jsa2V5PXoydHZhajh0NmtoYWRlZjd5ZHo3ODJ6a2Emc3Q9cXdlZjl5czAmZGw9MSIpICU+JQogIG11dGF0ZSgKICAgIG51dF90cnQgPSBmYWN0b3IoaWZlbHNlKG51dF90cnQgPT0iQyIsICIrY29tcG9zdCIsIGlmZWxzZShudXRfdHJ0ID09IkYiLCAiK04gZmVydGlsaXplciIsIGlmZWxzZShudXRfdHJ0ID09Ik4iLCAiY29udHJvbCIsIE5BKSkpLCBsZXZlbHMgPSBjKCJjb250cm9sIiwgIitOIGZlcnRpbGl6ZXIiLCAiK2NvbXBvc3QiKSksCiAgICBwcHRfdHJ0ID0gaWZlbHNlKHBwdF90cnQgPT0gIkQiLCAiZHJ5IiwgaWZlbHNlKHBwdF90cnQgPT0gIlhDIiwgImNvbnRyb2wiLCBpZmVsc2UocHB0X3RydCA9PSAiVyIsICJ3ZXQiLCBOQSkpKSkKCgojIERlZmluZSBhIHJldXNhYmxlIGNvbG9yIHNjYWxlCiMgY3VzdG9tX2NvbG9ycyA8LSBzY2FsZV9maWxsX21hbnVhbCgKIyAgIHZhbHVlcyA9IGMoCiMgICAgICJjb250cm9sIiA9IHJnYigxOTUsIDE5NywgMTkzLCBtYXhDb2xvclZhbHVlID0gMjUwKSwKIyAgICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDg3LCA2MiwgOTIsIG1heENvbG9yVmFsdWUgPSAyMjUpLAojICAgICAiK2NvbXBvc3QiID0gcmdiKDE2NywgMTU2LCAxMDksIG1heENvbG9yVmFsdWUgPSAyMjUpCiMgICApCiMgKQoKY3VzdG9tX2NvbG9ycyA8LSBzY2FsZV9maWxsX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopCgojIFNldCBhIGdsb2JhbCB0aGVtZQp0aGVtZV9zZXQodGhlbWVfYncoKSkKYGBgCgojIyBNYWtlIHNpdGUgeCBzcGVjaWVzIG1hdHJpeAoKMS4gIENhbGN1bGF0ZSByZWxhdGl2ZSBhYnVuZGFuY2VzIG9mIHNwZWNpZXMgZm9yIGVhY2ggc2l0ZQogICAgMS4gIGNvbmZ1c2VkIGhvdyB0byBhZ2dyZWdhdGUgYWJ1bmRhbmNlcyBiZWNhdXNlIGV2ZW4gZ3JvdXBpbmcgYnkgcGxvdGlkIChudXRfdHJ0IGFuZCBwcHRfdHJ0KSwgeWVhciwgc3BlY2llcywgYW5kIGdyYXppbmcgaGlzdG9yeSAoYmxvY2sgMSYyIC0tIGhpZ2gsIGJsb2NrIDMmNCAtLSBsb3cpIGFuZCBhdmVyYWdlZCwgdGhlIHNkIGFyZSBhcyBoaWdoIGFzIDQ1Ljk2IQogICAgICAgIDEuICBwcm9jZWVkZWQgd2l0aCB0aGVzZSBoaWdoIHNkIHRvIHNlZSB3aGF0IGhhcHBlbnMgKGFzayBMYXVyZW4pCiAgICAyLiAgdHJ5IGhvdyBpdCBpcyB3aGVuIHlvdSBzcGxpdCBldmVyeXRoaW5nIGJ5IGVhY2ggYmxvY2sgKG1vcmUgcmVwcmVzZW50YXRpdmU/KQoKYGBge3J9CnNpdGUuZGYgPC0gCiAgY292ZXIuZGF0LmxhYmVsc1ssIGMoMTo3LCAxODoxOSldICU+JSAjc3Vic2V0IGNvbHVtbnMKICBtdXRhdGUoCiAgICBncmF6aW5nX2hpc3QgPSBpZmVsc2UoYmxvY2sgPT0gMSB8IGJsb2NrID09IDIsICJoaWdoIiwgaWZlbHNlKGJsb2NrID09IDMgfCBibG9jayA9PSA0LCAibG93IiwgTkEpKQogICkgJT4lICMgc2VwYXJhdGUgYnkgYmxvY2sgKGdyYXppbmcgaW50ZW5zaXRpZXMpCiAgZ3JvdXBfYnkobnV0X3RydCwgcHB0X3RydCwgeXIsIGNvZGU0LCBncmF6aW5nX2hpc3QpICU+JSAjIG1ha2UgZWFjaCBjb2RlIHVuaXF1ZSAtLSBvbmUgdmFsdWUgZm9yIHNwZWNpZXMgYWJ1bmRhbmNlIGZvciBlYWNoIHRydAogIHN1bW1hcmlzZSgKICAgICMgcGN0X2NvdmVyLAogICAgYWJ1bmRhbmNlID0gbWVhbihwY3RfY292ZXIpCiAgICAjIHNkID0gc2QocGN0X2NvdmVyKQogICkKCm1hdHJpeDAgPC0gc3ByZWFkKAogIHNpdGUuZGYsIAogIGNvZGU0LCAKICBhYnVuZGFuY2UsIAogIGZpbGwgPSAwKQoKIyBtYWtlIHJvd25hbWVzIC0tLS0Kcm93bmFtZXMobWF0cml4MCkgPC0gcGFzdGUobWF0cml4MCRudXRfdHJ0LCBtYXRyaXgwJHBwdF90cnQsIG1hdHJpeDAkeXIsIG1hdHJpeDAkZ3JhemluZ19oaXN0LCBzZXAgPSAiXyIpCgojIGRlbGV0ZSBjb2x1bW5zIC0tLS0gCm1hdHJpeCA8LSBtYXRyaXgwWywgYyg1Ojc5KV0KCiMgcmVsYXRpdml6ZSBkYXRhIHdpdGggQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eQptYXRyaXguYnJheSA8LSBkZWNvc3RhbmQobWF0cml4LCAidG90YWwiKQpyb3duYW1lcyhtYXRyaXguYnJheSkgPC0gcm93bmFtZXMobWF0cml4MCkKYGBgCgojIyMgU3BsaXQgbWF0cml4IGJ5IGVhY2ggYmxvY2sgYXMgd2VsbAoKYGBge3J9CnNpdGUuYmxvY2suZGYgPC0gCiAgY292ZXIuZGF0LmxhYmVsc1ssIGMoMTo3LCAxODoxOSldICU+JSAjc3Vic2V0IGNvbHVtbnMKICBncm91cF9ieShudXRfdHJ0LCBwcHRfdHJ0LCB5ciwgY29kZTQsIGJsb2NrKSAlPiUgIyBtYWtlIGVhY2ggY29kZSB1bmlxdWUgLS0gb25lIHZhbHVlIGZvciBzcGVjaWVzIGFidW5kYW5jZSBmb3IgZWFjaCB0cnQKICBzdW1tYXJpc2UoCiAgICAjIHBjdF9jb3ZlciwKICAgIGFidW5kYW5jZSA9IG1lYW4ocGN0X2NvdmVyKQogICAgIyBzZCA9IHNkKHBjdF9jb3ZlcikKICApCgpzaXRlLmJsb2NrLnNkLmRmIDwtIAogIGNvdmVyLmRhdC5sYWJlbHNbLCBjKDE6NywgMTg6MTkpXSAlPiUgI3N1YnNldCBjb2x1bW5zCiAgZ3JvdXBfYnkobnV0X3RydCwgcHB0X3RydCwgeXIsIGNvZGU0LCBibG9jaykgJT4lICMgbWFrZSBlYWNoIGNvZGUgdW5pcXVlIC0tIG9uZSB2YWx1ZSBmb3Igc3BlY2llcyBhYnVuZGFuY2UgZm9yIGVhY2ggdHJ0CiAgc3VtbWFyaXNlKAogICAgcGN0X2NvdmVyLAogICAgYWJ1bmRhbmNlID0gbWVhbihwY3RfY292ZXIpLAogICAgc2QgPSBzZChwY3RfY292ZXIpCiAgKQoKbWF0cml4MC5ibG9jayA8LSBzcHJlYWQoCiAgc2l0ZS5ibG9jay5kZiwgCiAgY29kZTQsIAogIGFidW5kYW5jZSwgCiAgZmlsbCA9IDApCgojIG1ha2Ugcm93bmFtZXMgLS0tLQpyb3duYW1lcyhtYXRyaXgwLmJsb2NrKSA8LSBwYXN0ZShtYXRyaXgwLmJsb2NrJG51dF90cnQsIG1hdHJpeDAuYmxvY2skcHB0X3RydCwgbWF0cml4MC5ibG9jayR5ciwgbWF0cml4MC5ibG9jayRibG9jaywgc2VwID0gIl8iKQoKIyBkZWxldGUgY29sdW1ucyAtLS0tIAptYXRyaXguYmxvY2sgPC0gbWF0cml4MC5ibG9ja1ssIC1jKDA6NCldCgojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LmJsb2NrLmJyYXkgPC0gZGVjb3N0YW5kKG1hdHJpeC5ibG9jaywgInRvdGFsIikKcm93bmFtZXMobWF0cml4LmJsb2NrLmJyYXkpIDwtIHJvd25hbWVzKG1hdHJpeDAuYmxvY2spCmBgYAoKIyMgUnVuIE5NRFMKClJ1bGVzIG9mIHRodW1iOgoKLSAgIFw8IDAuMDUgaXMgKipleGNlbGxlbnQqKgoKLSAgIDAuMDUtMC4xIGlzICoqZ29vZCoqCgotICAgMC4xLTAuMiBpcyAqKmZhaXIqKgoKLSAgIDAuMi0wLjMgKippcyBjYXVzZSBmb3IgY29uY2Vybi4uLioqCgotICAgXD4gMC4zICoqaXMgcG9vciwgcmFuZG9tKioKCiMjIyBBbGwgeWVhcnMgLS0gbG93ICYgaGlnaCBncmF6aW5nCgpbU3RyZXNzOl17LnVuZGVybGluZX0gKmZhaXIqCgpgYGAgICAgICAgICAKMC4xOTY2NTUzIApgYGAKCkdyb3VwaW5nIGJ5IHllYXIgYW5kIGdyYXppbmcgaGlzdG9yeSBoYWQgbW9zdCBzaWduaWZpY2FudCBjbHVzdGVyaW5nIHNob3duLgoKIyMjIyMgbWV0YU1EUygpCgpgYGB7cn0Kbm1kcy5jb21wIDwtIG1ldGFNRFMobWF0cml4LmJyYXksIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuY29tcCAjIHByZXR0eSBub3QgZ3JlYXQgc3RyZXNzCnN0cmVzc3Bsb3Qobm1kcy5jb21wKQpwbG90KG5tZHMuY29tcCwgdHlwZT0idCIpCgpubWRzMSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLmNvbXAsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKG1hdHJpeDBbLCBjKDA6NCldKQpubWRzMiA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLmNvbXAsIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfZGF0IDwtIGNiaW5kKG5tZHMxLCBubWRzMikgJT4lCiAgc2VsZWN0KG51dF90cnQ6Z3JhemluZ19oaXN0LCBOTURTMSwgTk1EUzIpCgpgYGAKCiMjIyMjIHBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc19kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCwgY29sb3IgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBsYWJzKHRpdGxlID0gIkdyb3VwZWQgYnkgTnV0cmllbnQgVHJlYXRtZW50IikgKwogIGN1c3RvbV9jb2xvcnMgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopCgpnZ3Bsb3Qobm1kc19kYXQsIGFlcyhOTURTMSwgTk1EUzIsIGNvbG9yID0gYXMuZmFjdG9yKHlyKSwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBZZWFyIikKCmdncGxvdChubWRzX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgZmlsbCA9IGFzLmZhY3RvcihwcHRfdHJ0KSwgY29sb3IgPSBhcy5mYWN0b3IocHB0X3RydCkpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpICsKICBjdXN0b21fY29sb3JzICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQogICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDE0MCwgNDAsIDE1MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICMgVmlicmFudCBQdXJwbGUKICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwogICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKICAgICJkcnkiID0gcmdiKDE4MywgNjUsIDE0LCBtYXhDb2xvclZhbHVlID0gMjU1KQogICkKKQoKZ2dwbG90KG5tZHNfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IGFzLmZhY3RvcihncmF6aW5nX2hpc3QpLCBjb2xvciA9IGFzLmZhY3RvcihncmF6aW5nX2hpc3QpKSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBsYWJzKHRpdGxlID0gIkdyb3VwZWQgYnkgR3JhemluZyBIaXN0b3J5IikKCmdncGxvdChubWRzX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCksIGZpbGwgPSBhcy5mYWN0b3IoeXIpKSkgKwogIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBhcy5mYWN0b3IoeXIpKSwgc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDEpICsKICBzdGF0X2VsbGlwc2UoYWVzKGNvbG9yID0gYXMuZmFjdG9yKHlyKSksIAogICAgICAgICAgICAgICAgZ2VvbSA9ICJwb2x5Z29uIiwKICAgICAgICAgICAgICAgZmlsbCA9IE5BLAogICAgICAgICAgICAgICBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBHcmF6aW5nIEhpc3RvcnkgJiBZZWFyIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImxvdyIgPSAiY3lhbiIsCiAgICAiaGlnaCIgPSAiYnJvd24iLAogICIyMDE5IiA9ICJzYWxtb24iLAogICIyMDIwIiA9ICJsaW1lZ3JlZW4iLAogICIyMDIxIiA9ICJjb3JuZmxvd2VyYmx1ZSIpCiAgKQogIApnZ3Bsb3Qobm1kc19kYXQsIGFlcyhOTURTMSwgTk1EUzIsIGNvbG9yID0gbnV0X3RydCwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMSkgKwogIHN0YXRfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IobnV0X3RydCkpLAogICAgICAgICAgICAgZ2VvbSA9ICJwb2x5Z29uIiwKICAgICAgICAgICAgIGZpbGwgPSBOQSwgICMgTWFrZXMgdGhlIGVsbGlwc2UgdHJhbnNwYXJlbnQgaW5zaWRlCiAgICAgICAgICAgICBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBOdXRyaWVudCBUcmVhdG1lbnQgJiBZZWFyIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopCgpgYGAKCiMjIyBBbGwgeWVhcnMgLS0gYmxvY2tzCgpbU3RyZXNzOl17LnVuZGVybGluZX0gKmNhdXNlIGZvciBjb25jZXJuKgoKYGBgICAgICAgICAgCjAuMjMyOTMwNgpgYGAKCiMjIyMjIG1ldGFNRFMoKQoKYGBge3J9Cm5tZHMuYmxvY2suY29tcCA8LSBtZXRhTURTKG1hdHJpeC5ibG9jay5icmF5LCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLmJsb2NrLmNvbXAKc3RyZXNzcGxvdChubWRzLmJsb2NrLmNvbXApCnBsb3Qobm1kcy5ibG9jay5jb21wLCB0eXBlPSJ0IikKCm5tZHMxIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuYmxvY2suY29tcCwgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKSAlPiUKICBtdXRhdGUobWF0cml4MC5ibG9ja1ssIGMoMDo0KV0pCm5tZHMyIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuYmxvY2suY29tcCwgY2hvaWNlcz1jKDIpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kc19kYXQuYmxvY2sgPC0gY2JpbmQobm1kczEsIG5tZHMyKSAlPiUKICBzZWxlY3QobnV0X3RydDpibG9jaywgTk1EUzEsIE5NRFMyKQpgYGAKCiMjIyMjIHBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc19kYXQuYmxvY2ssIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCwgY29sb3IgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBsYWJzKHRpdGxlID0gIkdyb3VwZWQgYnkgTnV0cmllbnQgVHJlYXRtZW50IC0gQmxvY2tzIikgKwogIGN1c3RvbV9jb2xvcnMgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopCgpnZ3Bsb3Qobm1kc19kYXQuYmxvY2ssIGFlcyhOTURTMSwgTk1EUzIsIGNvbG9yID0gYXMuZmFjdG9yKHlyKSwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBZZWFyIC0gQmxvY2tzIikKCmdncGxvdChubWRzX2RhdC5ibG9jaywgYWVzKE5NRFMxLCBOTURTMiwgZmlsbCA9IGFzLmZhY3RvcihwcHRfdHJ0KSwgY29sb3IgPSBhcy5mYWN0b3IocHB0X3RydCkpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCAtIEJsb2NrcyIpICsKICBjdXN0b21fY29sb3JzICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQogICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDE0MCwgNDAsIDE1MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICMgVmlicmFudCBQdXJwbGUKICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwogICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKICAgICJkcnkiID0gcmdiKDE4MywgNjUsIDE0LCBtYXhDb2xvclZhbHVlID0gMjU1KQogICkKKQoKZ2dwbG90KG5tZHNfZGF0LmJsb2NrLCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IGFzLmZhY3RvcihibG9jayksIGNvbG9yID0gYXMuZmFjdG9yKGJsb2NrKSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IEJsb2NrIikKCmdncGxvdChubWRzX2RhdC5ibG9jaywgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gYXMuZmFjdG9yKGJsb2NrKSwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGFzLmZhY3Rvcih5cikpLCBzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMSkgKwogIHN0YXRfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoYmxvY2spKSwgCiAgICAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IEJsb2NrICYgWWVhciAtIEJsb2NrcyIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICMgImxvdyIgPSAiY3lhbiIsCiAgICAjICJoaWdoIiA9ICJicm93biIsCiAgIjIwMTkiID0gInNhbG1vbiIsCiAgIjIwMjAiID0gImxpbWVncmVlbiIsCiAgIjIwMjEiID0gImNvcm5mbG93ZXJibHVlIikKICApCiAgCmdncGxvdChubWRzX2RhdC5ibG9jaywgYWVzKE5NRFMxLCBOTURTMiwgY29sb3IgPSBudXRfdHJ0LCBmaWxsID0gYXMuZmFjdG9yKHlyKSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAxKSArCiAgc3RhdF9lbGxpcHNlKGFlcyhjb2xvciA9IGFzLmZhY3RvcihudXRfdHJ0KSksCiAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgZmlsbCA9IE5BLCAgIyBNYWtlcyB0aGUgZWxsaXBzZSB0cmFuc3BhcmVudCBpbnNpZGUKICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IE51dHJpZW50IFRyZWF0bWVudCAmIFllYXIgLSBCbG9ja3MiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikKYGBgCgojIyMgQWxsIHllYXJzIC0gTE9XIEdSQVpJTkcgT05MWQoKW1N0cmVzczpdey51bmRlcmxpbmV9ICpmYWlyKgoKYGBgICAgICAgICAgCjAuMTg2OTA2OApgYGAKCiMjIyMgZGF0YSB3cmFuZ2xpbmcKCmBgYHtyfQojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LmxvdyA8LSBtYXRyaXgwICU+JQogIGZpbHRlcihncmF6aW5nX2hpc3QgPT0gImxvdyIpCgpyb3cubG93IDwtIHBhc3RlKG1hdHJpeC5sb3ckbnV0X3RydCwgbWF0cml4LmxvdyRwcHRfdHJ0LCBtYXRyaXgubG93JHlyLCBtYXRyaXgubG93JGdyYXppbmdfaGlzdCwgc2VwID0gIl8iKQoKbWF0cml4LmxvdyA8LSBtYXRyaXgubG93WywgYyg1Ojc5KV0KCnJvd25hbWVzKG1hdHJpeC5sb3cpIDwtIHJvdy5sb3cKCm1hdHJpeC5icmF5LmxvdyA8LSBkZWNvc3RhbmQobWF0cml4LmxvdywgInRvdGFsIikKYGBgCgojIyMjIG1ldGFNRFMoKQoKYGBge3J9Cm5tZHMuY29tcC5sb3cgPC0gbWV0YU1EUyhtYXRyaXguYnJheS5sb3csIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuY29tcC5sb3cgIyBwcmV0dHkgbm90IGdyZWF0IHN0cmVzcwpzdHJlc3NwbG90KG5tZHMuY29tcC5sb3cpCnBsb3Qobm1kcy5jb21wLmxvdywgdHlwZT0idCIpCgpubWRzMSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLmNvbXAubG93LCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpICU+JQogIG11dGF0ZSgKICAgIG51dF90cnQgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LmxvdyksICJfIiksIGBbYCwgMSksCiAgICBwcHRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC5sb3cpLCAiXyIpLCBgW2AsIDIpLAogICAgeXIgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LmxvdyksICJfIiksIGBbYCwgMyksCiAgICBncmF6aW5nX2hpc3QgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LmxvdyksICJfIiksIGBbYCwgNCkKICApCm5tZHMyIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuY29tcC5sb3csIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfbG93X2RhdCA8LSBjYmluZChubWRzMSwgbm1kczIpICU+JQogIHNlbGVjdChudXRfdHJ0OmdyYXppbmdfaGlzdCwgTk1EUzEsIE5NRFMyKQpgYGAKCiMjIyMgcGxvdAoKYGBge3J9CmdncGxvdChubWRzX2xvd19kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBjb2xvciA9IGFzLmZhY3Rvcih5ciksIHNoYXBlID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBzdHJva2UgPSAxKSArIAogIGxhYnModGl0bGUgPSAiMjAxOS0yMDIxIChMT1cpIC0gR3JvdXBpbmcgYnkgWWVhciAmIE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc19sb3dfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGxhYnModGl0bGUgPSAiMjAxOS0yMDIxIChMT1cpIC0gR3JvdXBpbmcgYnkgTnV0cmllbnQgVHJlYXRtZW50IikrIAogIGN1c3RvbV9jb2xvcnMKCgpnZ3Bsb3Qobm1kc19sb3dfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMTktMjAyMSAoTE9XKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikgCgojIGFkZCB5ZWFyIGVsbGlwc2VzIC0tLS0gCmdncGxvdChubWRzX2xvd19kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgc3RhdF9lbGxpcHNlKGFlcyhjb2xvciA9IGFzLmZhY3Rvcih5cikpLCAKICAgICAgICAgICAgICAgIGdlb20gPSAicG9seWdvbiIsCiAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgc2l6ZSA9IDEpICsKICBsYWJzKHRpdGxlID0gIjIwMTktMjAyMSAoTE9XKSAtIEdyb3VwaW5nIGJ5IE51dHJpZW50IFRyZWF0bWVudCIpKyAKICBjdXN0b21fY29sb3JzCgoKZ2dwbG90KG5tZHNfbG93X2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBwcHRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICAgIHN0YXRfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoeXIpKSwgCiAgICAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAxOS0yMDIxIChMT1cpIC0gR3JvdXBpbmcgYnkgUHJlY2lwaXRhdGlvbiBUcmVhdG1lbnQiKSAKYGBgCgojIyBNYWtlIGVhY2ggaW5kaXZpZHVhbCB5ZWFyIE5NRFMgdG8gc2VlIGlmIHRoZXJlJ3MgYmV0dGVyIHN0cmVzcwoKIyMjIDIwMTkKCiMjIyMgZGF0YSB3cmFuZ2xpbmcKCmBgYHtyfQojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LjIwMTkgPC0gbWF0cml4MCAlPiUKICBmaWx0ZXIoeXIgPT0gMjAxOSkKCnJvdy4yMDE5IDwtIHBhc3RlKG1hdHJpeC4yMDE5JG51dF90cnQsIG1hdHJpeC4yMDE5JHBwdF90cnQsIG1hdHJpeC4yMDE5JHlyLCBtYXRyaXguMjAxOSRncmF6aW5nX2hpc3QsIHNlcCA9ICJfIikKCm1hdHJpeC4yMDE5IDwtIG1hdHJpeC4yMDE5WywgYyg1Ojc5KV0KCnJvd25hbWVzKG1hdHJpeC4yMDE5KSA8LSByb3cuMjAxOQoKbWF0cml4LmJyYXkuMjAxOSA8LSBkZWNvc3RhbmQobWF0cml4LjIwMTksICJ0b3RhbCIpCmBgYAoKIyMjIyBubWRzIDIwMTkKCltTdHJlc3M6XXsudW5kZXJsaW5lfSAqRXhjZWxsZW50KgoKYGBgICAgICAgICAgCjAuMDU2MDE3OApgYGAKCiMjIyMjIG1ldGFNRFMoKQoKYGBge3J9Cm5tZHMuMjAxOSA8LSBtZXRhTURTKG1hdHJpeC5icmF5LjIwMTksIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAxOSAjIHByZXR0eSBub3QgZ3JlYXQgc3RyZXNzCnN0cmVzc3Bsb3Qobm1kcy4yMDE5KQpwbG90KG5tZHMuMjAxOSwgdHlwZT0idCIpCgpubWRzMS4yMDE5IDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAxOSwgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKSAlPiUKICBtdXRhdGUoCiAgICBudXRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDE5KSwgIl8iKSwgYFtgLCAxKSwKICAgIHBwdF90cnQgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMTkpLCAiXyIpLCBgW2AsIDIpLAogICAgeXIgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMTkpLCAiXyIpLCBgW2AsIDMpLAogICAgZ3JhemluZ19oaXN0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDE5KSwgIl8iKSwgYFtgLCA0KQogICkKbm1kczIuMjAxOSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMTksIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfMjAxOV9kYXQgPC0gY2JpbmQobm1kczEuMjAxOSwgbm1kczIuMjAxOSkgJT4lCiAgc2VsZWN0KG51dF90cnQ6Z3JhemluZ19oaXN0LCBOTURTMSwgTk1EUzIpCmBgYAoKIyMjIyMgcGxvdAoKYGBge3J9CmdncGxvdChubWRzXzIwMTlfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgY29sb3IgPSBncmF6aW5nX2hpc3QsIHNoYXBlID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBzdHJva2UgPSAxKSArIAogIGxhYnModGl0bGUgPSAiMjAxOSAtIEdyb3VwaW5nIGJ5IEdyYXppbmcgSGlzdG9yeSAmIE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc18yMDE5X2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBsYWJzKHRpdGxlID0gIjIwMTkgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSsgCiAgY3VzdG9tX2NvbG9ycwoKCmdncGxvdChubWRzXzIwMTlfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMTkgLSBHcm91cGluZyBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpIAoKYGBgCgpgYGAgICAgICAgICAKYGBgCgojIyMgMjAyMAoKIyMjIyBkYXRhIHdyYW5nbGluZwoKYGBge3J9CiMgcmVsYXRpdml6ZSBkYXRhIHdpdGggQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eQptYXRyaXguMjAyMCA8LSBtYXRyaXgwICU+JQogIGZpbHRlcih5ciA9PSAyMDIwKQoKcm93LjIwMjAgPC0gcGFzdGUobWF0cml4LjIwMjAkbnV0X3RydCwgbWF0cml4LjIwMjAkcHB0X3RydCwgbWF0cml4LjIwMjAkeXIsIG1hdHJpeC4yMDIwJGdyYXppbmdfaGlzdCwgc2VwID0gIl8iKQoKbWF0cml4LjIwMjAgPC0gbWF0cml4LjIwMjBbLCBjKDU6NzkpXQoKcm93bmFtZXMobWF0cml4LjIwMjApIDwtIHJvdy4yMDIwCgptYXRyaXguYnJheS4yMDIwIDwtIGRlY29zdGFuZChtYXRyaXguMjAyMCwgInRvdGFsIikKYGBgCgojIyMjIG5tZHMgMjAyMAoKW1N0cmVzczpdey51bmRlcmxpbmV9ICpmYWlyKgoKYGBgICAgICAgICAgCjAuMTUyMjQ5NQpgYGAKCiMjIyMjIG1ldGFNRFMoKQoKYGBge3J9Cm5tZHMuMjAyMCA8LSBtZXRhTURTKG1hdHJpeC5icmF5LjIwMjAsIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAyMApzdHJlc3NwbG90KG5tZHMuMjAyMCkKcGxvdChubWRzLjIwMjAsIHR5cGU9InQiKQoKbm1kczEuMjAyMCA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjAsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKAogICAgbnV0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMCksICJfIiksIGBbYCwgMSksCiAgICBwcHRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIwKSwgIl8iKSwgYFtgLCAyKSwKICAgIHlyID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIwKSwgIl8iKSwgYFtgLCAzKSwKICAgIGdyYXppbmdfaGlzdCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMCksICJfIiksIGBbYCwgNCkKICApCm5tZHMyLjIwMjAgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIwLCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMjBfZGF0IDwtIGNiaW5kKG5tZHMxLjIwMjAsIG5tZHMyLjIwMjApICU+JQogIHNlbGVjdChudXRfdHJ0OmdyYXppbmdfaGlzdCwgTk1EUzEsIE5NRFMyKQpgYGAKCiMjIyMjIHBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc18yMDIwX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gZ3JhemluZ19oaXN0LCBzaGFwZSA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCwgc3Ryb2tlID0gMSkgKyAKICBsYWJzKHRpdGxlID0gIjIwMjAgLSBHcm91cGluZyBieSBHcmF6aW5nIEhpc3RvcnkgJiBOdXRyaWVudCBUcmVhdG1lbnQiKSAKCmdncGxvdChubWRzXzIwMjBfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjAgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMF9kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gcHB0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMCAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyMgMjAyMQoKIyMjIyBkYXRhIHdyYW5nbGluZwoKYGBge3J9CiMgcmVsYXRpdml6ZSBkYXRhIHdpdGggQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eQptYXRyaXguMjAyMSA8LSBtYXRyaXgwICU+JQogIGZpbHRlcih5ciA9PSAyMDIxKQoKcm93LjIwMjEgPC0gcGFzdGUobWF0cml4LjIwMjEkbnV0X3RydCwgbWF0cml4LjIwMjEkcHB0X3RydCwgbWF0cml4LjIwMjEkeXIsIG1hdHJpeC4yMDIxJGdyYXppbmdfaGlzdCwgc2VwID0gIl8iKQoKbWF0cml4LjIwMjEgPC0gbWF0cml4LjIwMjFbLCBjKDU6NzkpXQoKcm93bmFtZXMobWF0cml4LjIwMjEpIDwtIHJvdy4yMDIxCgptYXRyaXguYnJheS4yMDIxIDwtIGRlY29zdGFuZChtYXRyaXguMjAyMSwgInRvdGFsIikKYGBgCgojIyMjIyAyMDIxIC0gTE9XCgpTdHJlc3MKCmBgYCAgICAgICAgIAowLjA4MDY3Nzg5CmBgYAoKYGBge3J9CiMgcmVsYXRpdml6ZSBkYXRhIHdpdGggQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eQptYXRyaXguMjAyMS4xIDwtIG1hdHJpeDAgJT4lCiAgZmlsdGVyKHlyID09IDIwMjEsCiAgICAgICAgIGdyYXppbmdfaGlzdCA9PSAibG93IikgCgpyb3cuMjAyMS4xIDwtIHBhc3RlKG1hdHJpeC4yMDIxLjEkbnV0X3RydCwgbWF0cml4LjIwMjEuMSRwcHRfdHJ0LCBtYXRyaXguMjAyMS4xJHlyLCBtYXRyaXguMjAyMS4xJGdyYXppbmdfaGlzdCwgc2VwID0gIl8iKQoKbWF0cml4LjIwMjEuMSA8LSBtYXRyaXguMjAyMS4xWywgYyg1Ojc5KV0KCnJvd25hbWVzKG1hdHJpeC4yMDIxLjEpIDwtIHJvdy4yMDIxLjEKCm1hdHJpeC5icmF5LjIwMjEuMSA8LSBkZWNvc3RhbmQobWF0cml4LjIwMjEuMSwgInRvdGFsIikKYGBgCgpgYGB7cn0Kbm1kcy4yMDIxLjEgPC0gbWV0YU1EUyhtYXRyaXguYnJheS4yMDIxLjEsIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAyMS4xCnN0cmVzc3Bsb3Qobm1kcy4yMDIxLjEpCnBsb3Qobm1kcy4yMDIxLjEsIHR5cGU9InQiKQpkdW1teSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjEuMSwgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kczEuMjAyMS4xLmRmIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS4xLCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpICU+JQogIG11dGF0ZSh0cnQgPSByb3duYW1lcyhkdW1teSkpICU+JQogIHNlcGFyYXRlKHRydCwgYygibnV0X3RydCIsICJwcHRfdHJ0IiwgInByIiwgImdyYXppbmdfaGlzdCIpLCBzZXA9Il8iKQoKbm1kczIuMjAyMS4xIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS4xLCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMjFfZGF0LjEgPC0gY2JpbmQobm1kczEuMjAyMS4xLmRmLCBubWRzMi4yMDIxLjEpICU+JQogIHNlbGVjdChudXRfdHJ0OmdyYXppbmdfaGlzdCwgTk1EUzEsIE5NRFMyKQpgYGAKCmBgYHtyfQojIGdncGxvdChubWRzXzIwMjFfZGF0LjEsIGFlcyhOTURTMSwgTk1EUzIsICBjb2xvciA9IGdyYXppbmdfaGlzdCwgc2hhcGUgPSBudXRfdHJ0KSkgKwojICAgZ2VvbV9wb2ludChzaXplID0gNCwgc3Ryb2tlID0gMC41KSArCiMgICBsYWJzKHRpdGxlID0gIjIwMjEgLSBHcm91cGluZyBieSBHcmF6aW5nIEhpc3RvcnkgJiBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMV9kYXQuMSwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDIxIChMT1cpIC0gR3JvdXBpbmcgYnkgTnV0cmllbnQgVHJlYXRtZW50IikKCmdncGxvdChubWRzXzIwMjFfZGF0LjEsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gcHB0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMSAoTE9XKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyMjIyAyMDIxIC0gSElHSAoKU3RyZXNzCgpgYGAgICAgICAgICAKMC4wODA2NTAzNApgYGAKCmBgYHtyfQojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LjIwMjEuMiA8LSBtYXRyaXgwICU+JQogIGZpbHRlcih5ciA9PSAyMDIxLAogICAgICAgICBncmF6aW5nX2hpc3QgPT0gImhpZ2giKSAKCnJvdy4yMDIxLjIgPC0gcGFzdGUobWF0cml4LjIwMjEuMiRudXRfdHJ0LCBtYXRyaXguMjAyMS4yJHBwdF90cnQsIG1hdHJpeC4yMDIxLjIkeXIsIG1hdHJpeC4yMDIxLjIkZ3JhemluZ19oaXN0LCBzZXAgPSAiXyIpCgptYXRyaXguMjAyMS4yIDwtIG1hdHJpeC4yMDIxLjJbLCBjKDU6NzkpXQoKcm93bmFtZXMobWF0cml4LjIwMjEuMikgPC0gcm93LjIwMjEuMgoKbWF0cml4LmJyYXkuMjAyMS4yIDwtIGRlY29zdGFuZChtYXRyaXguMjAyMS4yLCAidG90YWwiKQpgYGAKCmBgYHtyfQpubWRzLjIwMjEuMiA8LSBtZXRhTURTKG1hdHJpeC5icmF5LjIwMjEuMiwgaz0yLCB0cnltYXggPSAyNSkKbm1kcy4yMDIxLjIKc3RyZXNzcGxvdChubWRzLjIwMjEuMikKcGxvdChubWRzLjIwMjEuMiwgdHlwZT0idCIpCmR1bW15IDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS4yLCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzMS4yMDIxLjIuZGYgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLjIsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKHRydCA9IHJvd25hbWVzKGR1bW15KSkgJT4lCiAgc2VwYXJhdGUodHJ0LCBjKCJudXRfdHJ0IiwgInBwdF90cnQiLCAicHIiLCAiZ3JhemluZ19oaXN0IiksIHNlcD0iXyIpCgpubWRzMi4yMDIxLjIgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLjIsIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfMjAyMV9kYXQuMiA8LSBjYmluZChubWRzMS4yMDIxLjIuZGYsIG5tZHMyLjIwMjEuMikgJT4lCiAgc2VsZWN0KG51dF90cnQ6Z3JhemluZ19oaXN0LCBOTURTMSwgTk1EUzIpCmBgYAoKYGBge3J9CmdncGxvdChubWRzXzIwMjFfZGF0LjIsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMSAoSElHSCkgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMV9kYXQuMiwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBwcHRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDIxIChISUdIKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyMjIG5tZHMgMjAyMQoKW1N0cmVzczpdey51bmRlcmxpbmV9ICpmYWlyKgoKYGBgICAgICAgICAgCjAuMTIzMDgzMQpgYGAKCiMjIyMjIG1ldGFNRFMoKQoKYGBge3J9Cm5tZHMuMjAyMSA8LSBtZXRhTURTKG1hdHJpeC5icmF5LjIwMjEsIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAyMQpzdHJlc3NwbG90KG5tZHMuMjAyMSkKcGxvdChubWRzLjIwMjEsIHR5cGU9InQiKQoKbm1kczEuMjAyMSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjEsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKAogICAgbnV0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMSksICJfIiksIGBbYCwgMSksCiAgICBwcHRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIxKSwgIl8iKSwgYFtgLCAyKSwKICAgIHlyID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIxKSwgIl8iKSwgYFtgLCAzKSwKICAgIGdyYXppbmdfaGlzdCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMSksICJfIiksIGBbYCwgNCkKICApCm5tZHMyLjIwMjEgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMjFfZGF0IDwtIGNiaW5kKG5tZHMxLjIwMjEsIG5tZHMyLjIwMjEpICU+JQogIHNlbGVjdChudXRfdHJ0OmdyYXppbmdfaGlzdCwgTk1EUzEsIE5NRFMyKQpgYGAKCiMjIyMjIHBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc18yMDIxX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gZ3JhemluZ19oaXN0LCBzaGFwZSA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCwgc3Ryb2tlID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICIyMDIxIC0gR3JvdXBpbmcgYnkgR3JhemluZyBIaXN0b3J5ICYgTnV0cmllbnQgVHJlYXRtZW50IikKCmdncGxvdChubWRzXzIwMjFfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMV9kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gcHB0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyMgMjAyMSAtLS0gYmxvY2tzCgojIyMjIGRhdGEgd3JhbmdsaW5nCgpgYGB7cn0KIyByZWxhdGl2aXplIGRhdGEgd2l0aCBCcmF5LUN1cnRpcyBkaXNzaW1pbGFyaXR5Cm1hdHJpeC4yMDIxLmJsb2NrIDwtIG1hdHJpeDAuYmxvY2sgJT4lCiAgZmlsdGVyKHlyID09IDIwMjEpCgpyb3cuMjAyMS5ibG9jayA8LSBwYXN0ZShtYXRyaXguMjAyMS5ibG9jayRudXRfdHJ0LCBtYXRyaXguMjAyMS5ibG9jayRwcHRfdHJ0LCBtYXRyaXguMjAyMS5ibG9jayR5ciwgbWF0cml4LjIwMjEuYmxvY2skYmxvY2ssIHNlcCA9ICJfIikKCm1hdHJpeC4yMDIxLmJsb2NrIDwtIG1hdHJpeC4yMDIxLmJsb2NrWywgYyg1Ojc5KV0KCnJvd25hbWVzKG1hdHJpeC4yMDIxLmJsb2NrKSA8LSByb3cuMjAyMS5ibG9jawoKbWF0cml4LmJyYXkuYmxvY2suMjAyMSA8LSBkZWNvc3RhbmQobWF0cml4LjIwMjEuYmxvY2ssICJ0b3RhbCIpCmBgYAoKIyMjIyBubWRzIDIwMjEKCltTdHJlc3M6XXsudW5kZXJsaW5lfSAqZmFpcioKCmBgYCAgICAgICAgIAowLjE3MDI5NDQKYGBgCgojIyMjIyBtZXRhTURTKCkKCmBgYHtyfQpubWRzLjIwMjEuYmxvY2sgPC0gbWV0YU1EUyhtYXRyaXguYnJheS5ibG9jay4yMDIxLCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLjIwMjEuYmxvY2sKc3RyZXNzcGxvdChubWRzLjIwMjEuYmxvY2spCnBsb3Qobm1kcy4yMDIxLmJsb2NrLCB0eXBlPSJ0IikKCm5tZHMxLjIwMjEuYmxvY2sgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLmJsb2NrLCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpICU+JQogIG11dGF0ZSgKICAgIG51dF90cnQgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjEuYmxvY2spLCAiXyIpLCBgW2AsIDEpLAogICAgcHB0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jayksICJfIiksIGBbYCwgMiksCiAgICB5ciA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jayksICJfIiksIGBbYCwgMyksCiAgICBibG9jayA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jayksICJfIiksIGBbYCwgNCkKICApCm5tZHMyLjIwMjEuYmxvY2sgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLmJsb2NrLCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMjFfZGF0LmJsb2NrIDwtIGNiaW5kKG5tZHMxLjIwMjEuYmxvY2ssIG5tZHMyLjIwMjEuYmxvY2spICU+JQogIHNlbGVjdChudXRfdHJ0OmJsb2NrLCBOTURTMSwgTk1EUzIpCmBgYAoKIyMjIyMgcGxvdAoKYGBge3J9CmdncGxvdChubWRzXzIwMjFfZGF0LmJsb2NrLCBhZXMoTk1EUzEsIE5NRFMyLCAgY29sb3IgPSBibG9jaywgc2hhcGUgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKwogIGxhYnModGl0bGUgPSAiMjAyMSAoQmxvY2spIC0gR3JvdXBpbmcgYnkgQmxvY2sgJiBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMV9kYXQuYmxvY2ssIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMSAoQmxvY2spIC0gR3JvdXBpbmcgYnkgTnV0cmllbnQgVHJlYXRtZW50IikKCmdncGxvdChubWRzXzIwMjFfZGF0LmJsb2NrLCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgKEJsb2NrKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyMgMjAyMSAtLS0gYmxvY2tzIChMT1cpCgojIyMjIGRhdGEgd3JhbmdsaW5nCgpgYGB7cn0KIyByZWxhdGl2aXplIGRhdGEgd2l0aCBCcmF5LUN1cnRpcyBkaXNzaW1pbGFyaXR5Cm1hdHJpeC4yMDIxLmJsb2NrLmxvdyA8LSBtYXRyaXgwLmJsb2NrICU+JQogIGZpbHRlcih5ciA9PSAyMDIxLAogICAgICAgICBibG9jayA9PSAzIHwgYmxvY2sgPT0gNCkKCnJvdy4yMDIxLmJsb2NrLmxvdyA8LSBwYXN0ZShtYXRyaXguMjAyMS5ibG9jay5sb3ckbnV0X3RydCwgbWF0cml4LjIwMjEuYmxvY2subG93JHBwdF90cnQsIG1hdHJpeC4yMDIxLmJsb2NrLmxvdyR5ciwgbWF0cml4LjIwMjEuYmxvY2subG93JGJsb2NrLCBzZXAgPSAiXyIpCgptYXRyaXguMjAyMS5ibG9jay5sb3cgPC0gbWF0cml4LjIwMjEuYmxvY2subG93WywgLWMoMDo0KV0KCnJvd25hbWVzKG1hdHJpeC4yMDIxLmJsb2NrLmxvdykgPC0gcm93LjIwMjEuYmxvY2subG93CgptYXRyaXguYnJheS5ibG9jay4yMDIxLmxvdyA8LSBkZWNvc3RhbmQobWF0cml4LjIwMjEuYmxvY2subG93LCAidG90YWwiKQpgYGAKCiMjIyMgbm1kcyAyMDIxCgpbU3RyZXNzOl17LnVuZGVybGluZX0gKmZhaXIqCgpgYGAgICAgICAgICAKMC4xMjgyMjk2CmBgYAoKIyMjIyMgbWV0YU1EUygpCgpgYGB7cn0Kbm1kcy4yMDIxLmJsb2NrLmxvdyA8LSBtZXRhTURTKG1hdHJpeC5icmF5LmJsb2NrLjIwMjEubG93LCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLjIwMjEuYmxvY2subG93CnN0cmVzc3Bsb3Qobm1kcy4yMDIxLmJsb2NrLmxvdykKcGxvdChubWRzLjIwMjEuYmxvY2subG93LCB0eXBlPSJ0IikKCm5tZHMxLjIwMjEuYmxvY2subG93IDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS5ibG9jay5sb3csIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKAogICAgbnV0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jay5sb3cpLCAiXyIpLCBgW2AsIDEpLAogICAgcHB0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jay5sb3cpLCAiXyIpLCBgW2AsIDIpLAogICAgeXIgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjEuYmxvY2subG93KSwgIl8iKSwgYFtgLCAzKSwKICAgIGJsb2NrID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIxLmJsb2NrLmxvdyksICJfIiksIGBbYCwgNCkKICApCm5tZHMyLjIwMjEuYmxvY2subG93IDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS5ibG9jay5sb3csIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfMjAyMV9kYXQuYmxvY2subG93IDwtIGNiaW5kKG5tZHMxLjIwMjEuYmxvY2subG93LCBubWRzMi4yMDIxLmJsb2NrLmxvdykgJT4lCiAgc2VsZWN0KG51dF90cnQ6YmxvY2ssIE5NRFMxLCBOTURTMikKYGBgCgojIyMjIyBwbG90CgpgYGB7cn0KZ2dwbG90KG5tZHNfMjAyMV9kYXQuYmxvY2subG93LCBhZXMoTk1EUzEsIE5NRFMyLCAgY29sb3IgPSBibG9jaywgc2hhcGUgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKwogIGxhYnModGl0bGUgPSAiMjAyMSAoQmxvY2s7IExPVykgLSBHcm91cGluZyBieSBCbG9jayAmIE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc18yMDIxX2RhdC5ibG9jay5sb3csIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMSAoQmxvY2s7IExPVykgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMV9kYXQuYmxvY2subG93LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgKEJsb2NrOyBMT1cpIC0gR3JvdXBpbmcgYnkgUHJlY2lwaXRhdGlvbiBUcmVhdG1lbnQiKQpgYGAKCiMjIyAyMDIxIC0tLSBibG9ja3MgKEhJR0gpCgojIyMjIGRhdGEgd3JhbmdsaW5nCgpgYGB7cn0KIyByZWxhdGl2aXplIGRhdGEgd2l0aCBCcmF5LUN1cnRpcyBkaXNzaW1pbGFyaXR5Cm1hdHJpeC4yMDIxLmJsb2NrLmhpZ2ggPC0gbWF0cml4MC5ibG9jayAlPiUKICBmaWx0ZXIoeXIgPT0gMjAyMSwKICAgICAgICAgYmxvY2sgPT0gMSB8IGJsb2NrID09IDIpCgpyb3cuMjAyMS5ibG9jay5oaWdoIDwtIHBhc3RlKG1hdHJpeC4yMDIxLmJsb2NrLmhpZ2gkbnV0X3RydCwgbWF0cml4LjIwMjEuYmxvY2suaGlnaCRwcHRfdHJ0LCBtYXRyaXguMjAyMS5ibG9jay5oaWdoJHlyLCBtYXRyaXguMjAyMS5ibG9jay5oaWdoJGJsb2NrLCBzZXAgPSAiXyIpCgptYXRyaXguMjAyMS5ibG9jay5oaWdoIDwtIG1hdHJpeC4yMDIxLmJsb2NrLmhpZ2hbLCAtYygwOjQpXQoKcm93bmFtZXMobWF0cml4LjIwMjEuYmxvY2suaGlnaCkgPC0gcm93LjIwMjEuYmxvY2suaGlnaAoKbWF0cml4LmJyYXkuYmxvY2suMjAyMS5oaWdoIDwtIGRlY29zdGFuZChtYXRyaXguMjAyMS5ibG9jay5oaWdoLCAidG90YWwiKQpgYGAKCiMjIyMgbm1kcyAyMDIxCgpbU3RyZXNzOl17LnVuZGVybGluZX0gKmZhaXIqCgpgYGAgICAgICAgICAKMC4xNDEyOTk3CmBgYAoKIyMjIyMgbWV0YU1EUygpCgpgYGB7cn0Kbm1kcy4yMDIxLmJsb2NrLmhpZ2ggPC0gbWV0YU1EUyhtYXRyaXguYnJheS5ibG9jay4yMDIxLmhpZ2gsIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAyMS5ibG9jay5oaWdoCnN0cmVzc3Bsb3Qobm1kcy4yMDIxLmJsb2NrLmhpZ2gpCnBsb3Qobm1kcy4yMDIxLmJsb2NrLmhpZ2gsIHR5cGU9InQiKQoKbm1kczEuMjAyMS5ibG9jay5oaWdoIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS5ibG9jay5oaWdoLCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpICU+JQogIG11dGF0ZSgKICAgIG51dF90cnQgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjEuYmxvY2suaGlnaCksICJfIiksIGBbYCwgMSksCiAgICBwcHRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIxLmJsb2NrLmhpZ2gpLCAiXyIpLCBgW2AsIDIpLAogICAgeXIgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjEuYmxvY2suaGlnaCksICJfIiksIGBbYCwgMyksCiAgICBibG9jayA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jay5oaWdoKSwgIl8iKSwgYFtgLCA0KQogICkKbm1kczIuMjAyMS5ibG9jay5oaWdoIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS5ibG9jay5oaWdoLCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMjFfZGF0LmJsb2NrLmhpZ2ggPC0gY2JpbmQobm1kczEuMjAyMS5ibG9jay5oaWdoLCBubWRzMi4yMDIxLmJsb2NrLmhpZ2gpICU+JQogIHNlbGVjdChudXRfdHJ0OmJsb2NrLCBOTURTMSwgTk1EUzIpCmBgYAoKIyMjIyMgcGxvdAoKYGBge3J9CmdncGxvdChubWRzXzIwMjFfZGF0LmJsb2NrLmhpZ2gsIGFlcyhOTURTMSwgTk1EUzIsICBjb2xvciA9IGJsb2NrLCBzaGFwZSA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCwgc3Ryb2tlID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICIyMDIxIChCbG9jazsgSElHSCkgLSBHcm91cGluZyBieSBCbG9jayAmIE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc18yMDIxX2RhdC5ibG9jay5oaWdoLCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgKEJsb2NrOyBISUdIKSAtIEdyb3VwaW5nIGJ5IE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc18yMDIxX2RhdC5ibG9jay5oaWdoLCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgKEJsb2NrOyBISUdIKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyBNYWtlIHNwZWNpZXMgeCB0cmFpdCBtYXRyaXgKCkdyZWVuaG91c2UgdHJhaXRzCgotICAgaGVpZ2h0LCBsZWFmIGRyeSBtYXR0ZXIgY29udGVudCwgc3BlY2lmaWMgbGVhZiBhcmVhLCByb290IG1hc3MgZnJhY3Rpb24sIHJlbGF0aXZlIGdyb3d0aCByYXRlLCBjb2Fyc2Ugcm9vdCBkaWFtZXRlciwgcm9vdCBkZW5zaXR5LCBzcGVjaWZpYyByb290IGxlbmd0aCBvZiBmaW5lIHJvb3RzLCBzcGVjaWZpYyByb290IGxlbmd0aCBvZiBjb2Fyc2Ugcm9vdHMKCkZpZWxkIHRyYWl0cwoKLSAgIGhlaWdodCwgbGVhZiBkcnkgbWF0dGVyIGNvbnRlbnQsIHNwZWNpZmljIGxlYWYgYXJlYSwgc2VlZCBtYXNzLCBsZWFmIEMsIGxlYWYgTgoKWyJIMTpdey51bmRlcmxpbmV9IFBhaXJpbmcgZmllbGQgcmVzdWx0cyB3aXRoIGEgZ3JlZW5ob3VzZSAxNSBOIGV4cGVyaW1lbnQgd2lsbCBhbGxvdyB1cyB0byByZWxhdGUgc3BlY2llcyByZXNwb25zZXMgdG8gdGhlaXIgYWJpbGl0eSB0byB1cHRha2Ugb3JnYW5pYyBOIgoKIkluIGFkZGl0aW9uLCB3ZSB3aWxsIGNvbmR1Y3QgYSBncmVlbmhvdXNlIGV4cGVyaW1lbnQgdG8gaXNvbGF0ZSB0aGUgbWVjaGFuaXNtIChtaW5lcmFsaXplZCBOIHZzIG9yZ2FuaWMgTiB1cHRha2UgcmF0ZXMgKSBieSB3aGljaCBjb21wb3N0IG1heSBhZmZlY3Qgc3BlY2llcyBjb21wb3NpdGlvbiIKCldvcmtmbG93IHBsYW46CgotICAgb3ZlcmxheSBzcGVjaWVzIHRyYWl0IGRhdGEgYXMgdmVjdG9ycyBvbiB0aGUgTk1EUwoKICAgIC0gICBvbmx5IGdyZWVuaG91c2UgdHJhaXRzIGF2YWlsYWJsZSAob25seSBzbGEgZGF0YSBmcm9tIGZpZWxkKQoKICAgICAgICAtICAgdXNlIFBDIHNjb3JlcyBhcyBjb21wb3NpdGUgdHJhaXQgYXhlcyBPUgoKICAgICAgICAtICAgYXZlcmFnZSB0aGUgdHJhaXRzIGZvciBlYWNoIHNwZWNpZXMKCiMjIyBSZWFkIGluIHRyYWl0IGRhdGEKCmBgYHtyfQojICMgcmVhZCBpbiBncmVlbmhvdXNlIHRyYWl0IGRhdGEKIyB0cmFpdHMuZ2ggPC0gcmVhZC5jc3YoImh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3NjbC9maS9jOHZrMzFhODA3eGc0OGplejFqMDMvR3JlZW5ob3VzZVRyYWl0cy5jc3Y/cmxrZXk9Y2E3MzZlYTI3azc5bW83aDhkYm42N3FpcSZzdD15YTFjazZwNyZkbD0xIikKIyAKIyAjIHJlYWQgaW4gZmllbGQgdHJhaXQgZGF0YQojICMgZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vc2NsL2ZpL3RycXJuejU0ZGtqb2E5ZG80dGxlNS9sZWFmLWFyZWEtZGF0YV9ORy54bHN4P3Jsa2V5PXMwa2ljMmE1eXFrbmlrYzRpY2VrOHk3cm4mc3Q9ZGw0eDYzNGgmZGw9MSIsZGVzdGZpbGUgPSAiZmllbGRfc2xhLnhsc3giKQojIHRyYWl0cy5zbGEuZmllbGQgPC0gCiMgICByZWFkX2V4Y2VsKCJmaWVsZF9zbGEueGxzeCIsY29sX25hbWVzID0gVFJVRSxjb2xfdHlwZXMgPSAidGV4dCIpCiMgCiMgcmRhKHRyYWl0cy5naCwgc2NhbGUgPSBUUlVFKQpgYGAKCiMjIyMgSW52ZXN0aWdhdGUgdHJhaXQgZGF0YSwgbG9va2luZyBpbiBHcmVlbmhvdXNlIHRyYWl0IGZvbGRlcgoKVHJhaXQgZGF0YSBpcyBpZGVudGljYWwuIFdpbGwgY2xlYW4gZGF0YSBpbgoKYGBge3J9CiMgZHJvcGJveC5tYWluIDwtIHJlYWQuY3N2KCJodHRwczovL3d3dy5kcm9wYm94LmNvbS9zY2wvZmkvYzh2azMxYTgwN3hnNDhqZXoxajAzL0dyZWVuaG91c2VUcmFpdHMuY3N2P3Jsa2V5PWNhNzM2ZWEyN2s3OW1vN2g4ZGJuNjdxaXEmc3Q9MGgxYnM1M2omZGw9MSIpCiMgCiMgZHJvcGJveC5naCA8LSByZWFkLmNzdigiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vc2NsL2ZpLzY3YWF1YmR5ZGl5NGl4ZmZtd3ZmZS9HcmVlbmhvdXNlVHJhaXRzLmNzdj9ybGtleT1ybTJlcWVxb21lN2hnb2VkaG5hbDBneDZkJnN0PXZreW02ZXZ4JmRsPTEiKQojIAojIGFsbC5lcXVhbChkcm9wYm94Lm1haW4sIGRyb3Bib3guZ2gpCiMgaWRlbnRpY2FsKGRyb3Bib3gubWFpbiwgZHJvcGJveC5naCkKYGBgCgpgYGB7cn0KdHJhaXRzLmNsZWFuZWQgPC0gcmVhZC5jc3YoImRhdGEvR3JlZW5ob3VzZVRyYWl0c19jb3JyZWN0ZWRfMjAyNDAyMTIuY3N2IikgJT4lCiAgbXV0YXRlKAogICAgRnJlc2gubGVhZi5tYXNzLi5nLiA9IGFzLm51bWVyaWMoaWZlbHNlKAogICAgICBGcmVzaC5sZWFmLm1hc3MuLmcuID09ICJTa2lwcGVkIGFjY2lkZW50YWxseSIsIE5BLCBGcmVzaC5sZWFmLm1hc3MuLmcuCiAgICApKSwKICAgIERyeS5sZWFmLm1hc3MuLmcuID0gYXMubnVtZXJpYyhpZmVsc2UoCiAgICAgIERyeS5sZWFmLm1hc3MuLmcuID09ICJObyBzYW1wbGUiLCBOQSwgRHJ5LmxlYWYubWFzcy4uZy4KICAgICkpLAogICAgUm9vdC5kcnkuYmlvbWFzcy4uZy4gPSBhcy5udW1lcmljKGlmZWxzZSgKICAgICAgUm9vdC5kcnkuYmlvbWFzcy4uZy4gPT0gInJvb3RzIGxvc3QiLCBOQSwgUm9vdC5kcnkuYmlvbWFzcy4uZy4KICAgICkpLAogICAgUm9vdC52b2x1bWUuLmNtMy4gPSBhcy5udW1lcmljKGlmZWxzZSgKICAgICAgUm9vdC52b2x1bWUuLmNtMy4gPT0gIm5vdCBzY2FubmVkIiwgTkEsIFJvb3Qudm9sdW1lLi5jbTMuCiAgICApKQogICkgCmBgYAoKIyMjIFN1bW1hcml6ZSB0cmFpdCBkYXRhIChHSCkgZm9yIGVhY2ggc3BlY2llcwoKIyMjIyBtZWFucwoKYGBge3J9CiMgbWFrZSB0cmFpdCBzcGVjaWVzIElEIG1hdGNoIG1hdHJpeCBkYXRhIChub3RlcyBzaG93biBiZWxvdykgLS0tLS0tLQp0cmFpdHMuY2xlYW5lZCA8LSB0cmFpdHMuY2xlYW5lZCAlPiUKICBtdXRhdGUoCiAgICBJRCA9IGlmZWxzZSgKICAgICAgSUQgPT0gIkFnb3NlcmlzIiwgIkFHU1AiLCBpZmVsc2UoCiAgICAgICAgSUQgPT0gIkFWRUJBUiIsICJBVkJBIiwgaWZlbHNlKAogICAgICAgICAgSUQgPT0gIkJSRFIiLCAiQlJESSIsIElECiAgICAgICAgKQogICAgICApCiAgICApCiAgKQoKIyBzdW1tYXJ5KHRyYWl0cy5jbGVhbmVkKQp0cmFpdHMubWVhbnMgPC0gdHJhaXRzLmNsZWFuZWQgJT4lCiAgZ3JvdXBfYnkoSUQpICU+JQogIHN1bW1hcmlzZSgKICAgIGFjcm9zcyg0OihuY29sKHRyYWl0cy5naCkgLSAxKSwgbGlzdChtZWFuID0gfm1lYW4oLngsIG5hLnJtID0gVFJVRSkKICApKSkKICAKCiMgbWFrZSBzaXRlIGJ5IHNwZWNpZXMgbWF0cml4IG1hdGNoIHRyYWl0cyBzcGVjaWVzCm1hdHJpeC5uYW1lcyA8LSBkYXRhLmZyYW1lKGNvbG5hbWVzKG1hdHJpeC5icmF5KSkgI3NwZWNpZXMgY29tcCAoNzUgY291bnQpCnRyYWl0Lm5hbWVzIDwtIGRhdGEuZnJhbWUodHJhaXRzLm1lYW5zJElEKSAjdHJhaXQgc3BlY2llcyAoODAgY291bnQpCgppbnRlcnNlY3QubmFtZXMgPC0gaW50ZXJzZWN0KGNvbG5hbWVzKG1hdHJpeC5icmF5KSwgdHJhaXRzLm1lYW5zJElEKSAjIHNhbWUgc3BlY2llcyAoNDMgY291bnQpCnNldGRpZmYoY29sbmFtZXMobWF0cml4LmJyYXkpLCB0cmFpdHMubWVhbnMkSUQpCnNldGRpZmYodHJhaXRzLm1lYW5zJElELCBjb2xuYW1lcyhtYXRyaXguYnJheSkpCgojIGNoZWNrIG1hdHJpeCBjb2RlcyB0byBzZWUgaWYgc2FtZSBzcGVjaWVzIGFyZSBuYW1lZCBkaWZmZXJlbnQgdGhpbmdzCnVuaXF1ZS5tYXRyaXguc3BlY2llcyA8LSBjb3Zlci5kYXQgJT4lCiAgZHBseXI6OnNlbGVjdChjb2RlNCwgc3BlY2llcykgJT4lCiAgc3VtbWFyaXNlKAogICAgY29kZTQgPSB1bmlxdWUoY29kZTQpLAogICAgc3BlY2llcyA9IHVuaXF1ZShzcGVjaWVzKQogICkKCnVuaXF1ZS50cmFpdC5zcGVjaWVzIDwtIHRyYWl0cy5jbGVhbmVkICU+JQogIGRwbHlyOjpzZWxlY3QoVGF4b24sIElEKSAlPiUKICBkaXN0aW5jdChJRCwgLmtlZXBfYWxsID0gVFJVRSkKICAKYGBgCgotICAgKioqY2hhbmdlKioqIFRyYWl0IG5hbWU6ICdBZ29zZXJpcycgLS1cPiAnQWdvc2VyaXMgdW5rbm93bic7IGFzc3VtaW5nIHRoZSBzYW1lIGFzICdBR1NQJyAtLVw+ICdBZ29zZXJpcyBzcC4nIGluIG1hdHJpeCBkYXRhIChjaGFuZ2UgdG8gbWF0cml4IG5hbWUpCgotICAgW1doYXQncyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuOl17LnVuZGVybGluZX0KCiAgICAtICAgJ0FOQVInIGFuZCAnQU5BUnAnIGluIHRyYWl0IGRhdGE/CgogICAgLSAgICdCUkhPJyBhbmQgJ0JSSE9wJyBpbiB0cmFpdCBkYXRhPwoKICAgIC0gICAnQlJOSWYnIGFuZCAnQlJOSXAnIGluIHRyYWl0IGRhdGE/IChub3QgaW4gbWF0cml4IGRhdGEpCgogICAgLSAgICdDTFBVZicgYW5kICdDTFBVcCcgaW4gdHJhaXQgZGF0YT8gKG5vdCBpbiBtYXRyaXggZGF0YSkKCiAgICAtICAgJ0dJVFJmJyBhbmQgJ0dJVFJwJyBpbiB0cmFpdCBkYXRhPyAobm90IGluIG1hdHJpeCBkYXRhKQoKICAgIC0gICAnTEVOSWYnIGFuZCAnTEVOSXAnIGluIHRyYWl0IGRhdGE/IChub3QgaW4gbWF0cml4IGRhdGEpCgogICAgLSAgICdUUkhJJyBhbmQgJ1RSSElwaScgKHNhbWUgc3AgbmFtZSkgaW4gdHJhaXQgZGF0YT8gKFRSSEkgaW4gbWF0cml4IGRhdGEpCgogICAgLSAgICdUUldJZicgYW5kICdUUldJcCcgYW5kICdUUldJcGknIGluIHRyYWl0IGRhdGE/IChub3QgaW4gbWF0cml4IGRhdGEpCgogICAgLSAgICdDcmFzc3VsYScgYW5kICdDcmFzc3VsYSB0aWxsYWVhJyAoY291bGQgdGhleSBiZSB0aGUgc2FtZT8pCgogICAgLSAgICdTYW5pY3VsYScgKHVua25vd24pIGFuZCAnU0FCSTEnIG9yICdTQUJJMicgKGNvdWxkIHRoZXkgYmUgdGhlIHNhbWU/KQoKICAgIC0gICAnTUFFTGYnICh0cmFpdCBkYXRhKSBhbmQgJ01BRDEnIChNYWRpYSBzcC4gMSAoInRhbGwgdGFyd2VlZCIpJyAoY291bGQgdGhleSBiZSB0aGUgc2FtZT8pCgogICAgLSAgICdNQUVMcCcgKHRyYWl0IGRhdGEpIGFuZCAnTUFEMicgKE1hZGlhIHNwLiAxICgic21hbGwgdGFyd2VlZCIpJyAoY291bGQgdGhleSBiZSB0aGUgc2FtZT8pCgogICAgLSAgICdUcmlmb2xpdW0gZXJpb2NlcGhhbHVtJyAoVFJFUikgYW5kICdUcmlwaHlzYXJpYSBlcmlhbnRoYScgKFRSRVIpIChjb3VsZCB0aGV5IGJlIHRoZSBzYW1lPykKCi0gICAqKipjaGFuZ2UqKiogJ0FWRUJBUicgKHRyYWl0IGRhdGEpIHRvICdBVkJBJyAobWF0cml4IGRhdGEpCgotICAgKioqY2hhbmdlKioqIEJSRFIgLS1cPiBCUkRJCgojIyBPdmVybGF5IFRyYWl0IFZlY3RvcnMgb250byBOTURTCgojIyMgQUxMIFlFQVJTIC0tIExPVyBBTkQgSElHSCBHUkFaSU5HCgojIyMjIFByZXBhcmUgTk1EUyBhbmQgVHJhaXRzCgpTdHJlc3M6CgpgYGAgICAgICAgICAKMC4yMDExMTI3CmBgYAoKYGBge3J9CiMgc3Vic2V0IG5tZHMgdG8gbWF0Y2ggc3BlY2llcyBuYW1lcwpubWRzLmNvbXAudHJhaXQgPC0gbWV0YU1EUyhtYXRyaXguYnJheSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGludGVyc2VjdC5uYW1lcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBrPTIsIHRyeW1heCA9IDI1KQpubWRzLmNvbXAudHJhaXQgIyBwcmV0dHkgbm90IGdyZWF0IHN0cmVzcwpzdHJlc3NwbG90KG5tZHMuY29tcC50cmFpdCkKcGxvdChubWRzLmNvbXAudHJhaXQsIHR5cGU9InQiKQoKbm1kczEgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy5jb21wLnRyYWl0LCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCm5tZHMyIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuY29tcC50cmFpdCwgY2hvaWNlcz1jKDIpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kc19kYXRfdHJhaXQgPC0gY2JpbmQobm1kczEsIG5tZHMyKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lICAjIEVuc3VyZSBpdCdzIGEgZGF0YSBmcmFtZQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAic2l0ZV9pZCIpICU+JSAgIyBNb3ZlIHJvdyBuYW1lcyBpbnRvIGEgbmV3IGNvbHVtbgogIHNlcGFyYXRlKHNpdGVfaWQsIGludG8gPSBjKCJudXRfdHJ0IiwgInBwdF90cnQiLCAieXIiLCAiZ3JhemluZ19oaXN0IiksIHNlcCA9ICJfIikKCgojIHN1YnNldCBtYXRyaXggYW5kIHRyYWl0IGRhdGEgdG8gbWF0Y2ggbmFtZXMKdHJhaXRzLm1lYW5zLmNvbXAgPC0gdHJhaXRzLm1lYW5zICU+JQogIGZpbHRlcihJRCAlaW4lIGludGVyc2VjdC5uYW1lcykgJT4lCiAgcmVuYW1lKAogICAgSGVpZ2h0ID0gSGVpZ2h0Li5jbS5fbWVhbiwKICAgIEZyZXNoTGVhZk1hc3MgPSBGcmVzaC5sZWFmLm1hc3MuLmcuX21lYW4sCiAgICBEcnlMZWFmTWFzcyA9IERyeS5sZWFmLm1hc3MuLmcuX21lYW4sCiAgICBMRE1DID0gTERNQ19tZWFuLCAjIExlYWYgZHJ5IG1hdHRlciBjb250ZW50IChMRE1DLCB0aGUgcmF0aW8gb2YgbGVhZiBkcnkgbWFzcyB0byBmcmVzaCBtYXNzKQogICAgTGVhZkFyZWEgPSBMZWFmLkFyZWEuLmNtMi5fbWVhbiwKICAgIFNMQSA9IFNMQS4uY20yLmcuX21lYW4sCiAgICBTaG9vdERyeUJpb21hc3MgPSBTaG9vdC5kcnkuYmlvbWFzcy4uZy5fbWVhbiwKICAgIFJvb3REcnlCaW9tYXNzID0gUm9vdC5kcnkuYmlvbWFzcy4uZy5fbWVhbiwKICAgIFRvdGFsQmlvbWFzcyA9IFRvdGFsLmJpb21hc3MuLmcuX21lYW4sCiAgICBSTUYgPSBSTUZfbWVhbiwgIyBSb290IG1hc3MgZnJhY3Rpb24gKFJNRikgaXMgYSBwbGFudCB0cmFpdCB0aGF0IG1lYXN1cmVzIHRoZSBwcm9wb3J0aW9uIG9mIGEgcGxhbnQncyBkcnkgbWFzcyB0aGF0IGlzIGluIGl0cyByb290cwogICAgUm9vdFZvbCA9IFJvb3Qudm9sdW1lLi5jbTMuX21lYW4sCiAgICBSb290RGVuc2l0eSA9IFJvb3QuZGVuc2l0eS4uZy5jbTMuX21lYW4sCiAgICBDb2Fyc2VSb290RGlhbWV0ZXIgPSBDb2Fyc2Uucm9vdC5kaWFtZXRlci4ubW0uX21lYW4sCiAgICBSb290TGVuZ3RoID0gTGVuZ3RoLi5tbS5fbWVhbiwKICAgIEZpbmVSb290TGVuZ3RoID0gRmluZS5yb290Lmxlbmd0aC4ubW0uX21lYW4sCiAgICBDb2Fyc2VSb290TGVuZ3RoID0gQ29hcnNlLnJvb3QubGVuZ3RoLi5tbS5fbWVhbiwKICAgIENvYXJzZVJvb3RTcGVjTGVuZ3RoID0gQ29hcnNlLnJvb3Quc3BlY2lmaWMubGVuZ3RoLi5jbS5nLl9tZWFuLAogICAgRmluZVJvb3RTcGVjTGVuZ3RoID0gRmluZS5yb290LnNwZWNpZmljLmxlbmd0aC4uY20uZy5fbWVhbiwKICAgIFByb3BGaW5lUm9vdHMgPSBQcm9wb3J0aW9uLmZpbmUucm9vdHNfbWVhbgogICAgCiAgKQojIHRyYWl0cy5tZWFucy5jb21wMiA8LSB0cmFpdHMubWVhbnMuY29tcCAlPiUKIyBkcGx5cjo6c2VsZWN0KC1JRCkKcm93bmFtZXModHJhaXRzLm1lYW5zLmNvbXAyKSA8LSB0cmFpdHMubWVhbnMuY29tcCRJRAoKIyB0cmFpdCB2ZWN0b3JzIG9udG8gdGhlIE5NRFMKIyBlbnZmaXQobm1kcy5jb21wLnRyYWl0LCB0cmFpdHMubWVhbnMuY29tcCwgcGVybXV0YXRpb25zID0gOTk5KQojIGV4YW1wbGUgZnJvbSBzdGFjayBvdmVyZmxvdzogZW52Zml0KG9yZCB+IHZhcjEgKyB2YXIyICsgdmFyMywgZHVuZS5zcGVjLCBkaXNwbGF5PSJzcCIpLCAnb3JkJyBpcyB0aGUgbm1kcyBtb2RlbCwgJ3ZhcjEnIGlzIHRoZSB0cmFpdDEgaSB0aGluaz8KCmNvbG5hbWVzKHRyYWl0cy5tZWFucy5jb21wKQp2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCA8LSBlbnZmaXQobm1kcy5jb21wLnRyYWl0IH4gSGVpZ2h0ICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExlYWZBcmVhICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUk1GLCB0cmFpdHMubWVhbnMuY29tcCwgZGlzcGxheSA9ICJzcCIpICMgT05MWSBIZWlnaHQsIExlYWYgYXJlYSwgYW5kIFJNRiBzaWduaWZpY2FudAoKIyBpcyBpdCBkaWZmZXJlbnQgd2hlbiB5b3Ugb25seSBkbyBjZXJ0YWluIHRyYWl0cyAoYWJvdmUtIHZzLiBiZWxvdy1ncm91bmQpPyBvciBjYW4geW91IGp1c3QgdGhyb3cgZXZlcnl0aGluZyBpbiB0aGVyZSBhbmQgaXQgd2lsbCB0ZWxsIHlvdSB3aGF0IGlzIHNpZ25pZmljYW50IGFuZCB5b3UgY2FuIHN1YnNldCBmcm9tIHRoZXJlPwoKIyBMb29rcyBsaWtlIGRpZmZlcmVudCBzdWJzZXRzIG9mIHRyYWl0cyBwdXQgaW4gYXJlIHRoZSBzYW1lLCBzbyBJIHNoYWxsIHByb2NlZWQgd2l0aCB0aGUgbWVnYSBtb2RlbHMgYW5kIHZlcmlmeSB3aXRoIExhdXJlbgoKdHJhaXRfdmVjdG9ycyA8LSBhcy5kYXRhLmZyYW1lKHZlY3RvcnMubm1kcy5jb21wLnRyYWl0JHZlY3RvcnMkYXJyb3dzKQpgYGAKCk5NRFMgbW9kZWw6IG9ubHkgSGVpZ2h0LCBMZWFmIGFyZWEsIGFuZCBSTUYgKCkgZm91bmQgc2lnbmlmaWNhbnQuCgojIyMjIFBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc19kYXRfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCwgY29sb3IgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBsYWJzKHRpdGxlID0gIkdyb3VwZWQgYnkgTnV0cmllbnQgVHJlYXRtZW50IikgKwogIGN1c3RvbV9jb2xvcnMgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICAgIHZhbHVlcyA9IGMoCiAgICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQogICAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKICAgICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgICApCiAgKSArCiAgZ2VvbV9zZWdtZW50KAogICAgZGF0YSA9IGFzLmRhdGEuZnJhbWUodmVjdG9ycy5ubWRzLmNvbXAudHJhaXQkdmVjdG9ycyRhcnJvd3MpLCAKICAgIGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBOTURTMSwgeWVuZCA9IE5NRFMyKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyDwn5qAIFByZXZlbnRzIGl0IGZyb20gbG9va2luZyBmb3IgJ251dF90cnQnCiAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSksIAogICAgY29sb3IgPSAicmVkIiwgCiAgICBzaXplID0gMQogICkgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSBhcy5kYXRhLmZyYW1lKHZlY3RvcnMubm1kcy5jb21wLnRyYWl0JHZlY3RvcnMkYXJyb3dzKSwgCiAgICBhZXMoeCA9IE5NRFMxLCB5ID0gTk1EUzIsIGxhYmVsID0gcm93bmFtZXModmVjdG9ycy5ubWRzLmNvbXAudHJhaXQkdmVjdG9ycyRhcnJvd3MpKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyBBdm9pZHMgdW53YW50ZWQgaW5oZXJpdGFuY2UKICAgIGhqdXN0ID0gLTAuMiwgCiAgICB2anVzdCA9IC0wLjIsIAogICAgY29sb3IgPSAicmVkIiwKICAgIHNpemUgPSA1CiAgKQoKIyBnZ3Bsb3Qobm1kc19kYXRfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsIGNvbG9yID0gYXMuZmFjdG9yKHlyKSwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiMgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiMgICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKIyAgIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBZZWFyIikKIyAKIyBnZ3Bsb3Qobm1kc19kYXRfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsIGZpbGwgPSBhcy5mYWN0b3IocHB0X3RydCksIGNvbG9yID0gYXMuZmFjdG9yKHBwdF90cnQpKSkgKwojICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAojICAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiMgICBsYWJzKHRpdGxlID0gIkdyb3VwZWQgYnkgUHJlY2lwaXRhdGlvbiBUcmVhdG1lbnQiKSArCiMgICBjdXN0b21fY29sb3JzICsKIyAgIHNjYWxlX2NvbG9yX21hbnVhbCgKIyAgIHZhbHVlcyA9IGMoCiMgICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQojICAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQojICAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKIyAgICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKIyAgICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiMgICApCiMgKQoKIyBnZ3Bsb3Qobm1kc19kYXRfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCksIGNvbG9yID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCkpKSArCiMgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiMgICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKIyAgIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBHcmF6aW5nIEhpc3RvcnkiKQojIAojIGdncGxvdChubWRzX2RhdF90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCksIGZpbGwgPSBhcy5mYWN0b3IoeXIpKSkgKwojICAgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGFzLmZhY3Rvcih5cikpLCBzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMSkgKwojICAgc3RhdF9lbGxpcHNlKGFlcyhjb2xvciA9IGFzLmZhY3Rvcih5cikpLCAKIyAgICAgICAgICAgICAgICAgZ2VvbSA9ICJwb2x5Z29uIiwKIyAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiMgICAgICAgICAgICAgICAgc2l6ZSA9IDEpICsKIyAgIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBHcmF6aW5nIEhpc3RvcnkgJiBZZWFyIikgKwojICAgc2NhbGVfY29sb3JfbWFudWFsKAojICAgdmFsdWVzID0gYygKIyAgICAgImxvdyIgPSAiY3lhbiIsCiMgICAgICJoaWdoIiA9ICJicm93biIsCiMgICAiMjAxOSIgPSAic2FsbW9uIiwKIyAgICIyMDIwIiA9ICJsaW1lZ3JlZW4iLAojICAgIjIwMjEiID0gImNvcm5mbG93ZXJibHVlIikKIyAgICkKICAKIyBnZ3Bsb3Qobm1kc19kYXRfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsIGNvbG9yID0gbnV0X3RydCwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiMgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAxKSArCiMgICBzdGF0X2VsbGlwc2UoYWVzKGNvbG9yID0gYXMuZmFjdG9yKG51dF90cnQpKSwKIyAgICAgICAgICAgICAgZ2VvbSA9ICJwb2x5Z29uIiwKIyAgICAgICAgICAgICAgZmlsbCA9IE5BLCAgIyBNYWtlcyB0aGUgZWxsaXBzZSB0cmFuc3BhcmVudCBpbnNpZGUKIyAgICAgICAgICAgICAgc2l6ZSA9IDEpICsKIyAgIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBOdXRyaWVudCBUcmVhdG1lbnQgJiBZZWFyIikgKwojICAgc2NhbGVfY29sb3JfbWFudWFsKAojICAgdmFsdWVzID0gYygKIyAgICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiMgICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiMgICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwojICAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAojICAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKIyAgICkKIyApCmBgYAo=